Problème Tableaux et Msgbox
Bonjour à tous et merci de donner du temps!
Je réalise un projet sur cette base de donnée ci-jointe et je rencontre des problèmes sur 3 macros au niveau des msgbox et de l'affichage de tableaux.
J'ai mis des remarques dans le fichier.
Merci d'avance!
Bonsoir,
C'est pas gagné !
J'ai un peu regardé ta Macro1... et je m'en tiendrai là car j'ai déjà souligné il me semble que le code non indenté est particulièrement pénible à lire, et si tu ne te mets pas au moins à indenter correctement ton code, je refuse pour ma part d'y jeter le moindre regard.
Par ailleurs, ce que j'ai vu m'incite à te recommander une sérieuse révision des rudiments de VBA car les lacunes qui apparaissent en la matière sont plutôt nombreuses.
D'abord tes macros, qui ne sont pas évènementielles, ni liées à des macros d'évènements, n'ont rien à faire dans un module de feuille, leur place est dans un module Standard ! Cela fait partie de règles de base à respecter et c'est en les respectant qu'on s'y retrouve le mieux !
Ta macro se termine par :
MsgBox("Z", 65, "Meilleur département pour le secteur d'activité choisi")que tu commentes par :
'ici, lorsque j'active la ligne, excel me demande de rajouter un =
HéBé oui !
Savais-tu déjà que MsgBox est une fonction ?
La particularité d'une fonction est de renvoyer un résultat. Lorsque tu as l'intention de récupérer le résultat de la fonction, tu peux utiliser une variable à cette fin :
rép = MsgBox("Voulez-vous continuer ?", vbQuestion + vbYesNo, "Poursuivre la recherche")et tu récupèreras dans rép une valeur correspondant à vbYes (oui) ou vbNo (non).
Ou bien tu peux l'utiliser sous condition :
If Msgbox("Voulez-vous continuer ?", vbQuestion + vbYesNo, "Poursuivre la recherche") = _
vbNo Then Exit SubLà si la réponse est non tu sors, sinon tu continues.
Mais si tu n'attends pas de réponse au message, à ce moment-là tu utilises la fonction dans les mêmes conditions qu'une procédure Sub, et tu ne mets pas les arguments entre parenthèses !
MsgBox "Fini !", vbInformation, "Recherche"Continuons avec la même ligne : 65, moi je ne sais pas spontanément ce que cela signifie ! Toi non plus je gage !
vbInformation + vbOKCancel c'est tout de même plus parlant que 65 (même si pour VBA c'est la même chose...)
Mais VBA exécute sans réfléchir, et affiche une erreur s'il ne peut aller au bout de l'exécution, mais nous, nous pouvons nous demander pourquoi on demande à l'utilisateur de choisir entre OK et Annuler en lui présentant un résultat de recherche !
C'est sans doute une erreur, mais en écrivant 65, cela empêche de la percevoir !
En tout état de cause le résultat qui doit être affiché a été récupéré dans la variable Z, mais l'utilisateur aura bien du mal à le découvrir car en lui mettant "Z" entre guillemets, la seule chose qu'il verra est un Z
Ça fait pas mal pour une seule ligne de code ! Et ça t'indique déjà plusieurs chapitres à réviser !
MsgBox Z, vbInformation, "Meilleur département pour le secteur d'activité choisi"Voilà déjà cette ligne correctement rétablie, mais on n'en a pas fini car :
Z = Meilleurdepart(secteur)La valeur de Z fait appel à une fonction (Meilleurdepart) en lui passant l'argument secteur, lequel est constitué par la saisie de l'utilisateur dans une InputBox.
Notons que cette méthode est loin d'être très ergonomique, ni fiable on le verra mais pour l'instant (avant d'aller voir ce qui se passe dans la fonction), on ne peut que constater que la valeur de Z renvoyée est vide, rien, néant !
à suivre...
Passons donc à la fonction :
Function Meilleurdepart(valeur As String)et sans tourner longtemps disons tout de suite que sa structure est totalement défectueuse !
Pourquoi ? Parce que :
For nl = 6 To nombreligneson parcourt les lignes de la base de données (déterminées avec .UsedRange.Rows.Count, ce qui n'est pas la meilleure façon, et risque fort d'en ajouter au moins quelques unes...)
Et à chaque ligne on opère une série de tests indépendants les uns des autres :
If StrComp(valeur, "agriculture") = 0 Then If StrComp(valeur, "industrie") = 0 Then5 ainsi... On va donc tester 5 fois valeur (qui constitue l'argument de la fonction, saisie par l'opérateur) à chaque ligne même si on l'a déjà trouvé !
Ceci étant, si l'utilisateur a saisi : Agriculture ou Industrie... on ne le trouvera jamais !
Il y a là une mauvaise utilisation de la fonction StrComp qui comporte un 3e argument qui aurait dû être défini en vbTextCompare de façon que la fonction opère en comparaison de texte.
Ce qui n'aurait cependant pas empêché des fautes de frappe... et l'on sait que la fiabilisation d'un tel choix passe par un Userform doté d'une ComboBox listant les choix possibles pour l'utilisateur, ce qui élimine toute erreur de ce type...
Revenons sur la structure : valeur permet de cibler la colonne de recherche (7 à 11), il est donc clair qu'au démarrage de la fonction on aurait dû tester valeur pour placer le numéro de colonne dans une variable, ce qui éliminait d'emblée ces conditions successives (qu'on n'avait même pas relié par des ElseIf de façon à réduire un peu ce parcours...
Mais cela ne sera pas suffisant pour trouver !
Les conditions sont bâties de cette façon :
If StrComp(valeur, "industrie") = 0 Then
a = Cells(nl, 8).Value
If a < Cells(nl, 8).Value Then
b = Cells(nl, 8).Value
End If
End IfNB-J'indente, car d'une part c'est insupportable à lire, et d'autre part ça révèle la signification (noyée quand ce n'est pas indenté).
a prend la valeur de la cellule. Et si a est inférieur à cette valeur, b la prendra !
Comme a sera égal à la valeur qu'on vient de lui donner, b ne prendra jamais rien et sera égal à 0 !
Là je dois dire que je me perds en conjecture sur les raisons qui ont conduit à cela !
Mais relativisons ! Ce n'est pas la dernière surprise ! A la fin on n'utilisera ni a ni b !!!
Mais restons sur la condition : ce qu'on recherche c'est la plus grande valeur dans la colonne afin de renvoyer le département correspondant qui figure en colonne 2. On a donc besoin de mémoriser la plus grande valeur au fil du parcours, et la ligne sur laquelle elle se trouve, et remplacer ces valeurs chaque fois que l'on en trouve une supérieure...
Gardons les variables a et b, a pour la plus grande valeur, b pour la ligne. La condition aurait dû se présenter ainsi :
If a < Cells(nl, k).Value Then
a = Cells(nl, k).Value
b = nl
End IfJ'en profite pour considérer qu'un test antérieur a défini la colonne à parcourir (variable k), et les 5 double-conditions sont remplacées par cette seule et unique. La boucle se terminera alors avec b ayant le numéro de ligne correspondant au département cherché, qu'il suffira d'aller prendre dans sa colonne.
Mais la fonction se termine ainsi :
Meilleurdepart = "text"
Meilleurdepart = Cells(nl, 2).Value & ""text mais in-extremis on lui fait renvoyer la valeur de la ligne nl en colonne B.
A la fin de la boucle For... Next nl a la valeur 107. Et la cellule B107 est vide.
Est-ce pour conforter cette valeur qu'on croit bon de lui ajouter & "", une chaîne vide !
La bonne fin était :
Meilleurdepart = Cells(b, 2).Valueaprès avoir réduit la longueur de la fonction d'au moins les 3/4...
Reste un point que je n'ai pas soulevé (mais il y en a certainement d'autres...), ce Cells qui apparaît ici, tout nu, sans point devant !
Ayant commencé sur une macro, parce qu'elle me paraissait courte
Cordialement.
Bonjour à tous et merci de donner du temps!!
Je tenais à vous remercier sincèrement pour les messages sur mon sujet qui m'ont été d'une grande aide! Malheureusement je débute en VBA et mes cours ne sont ni complets ni clairs... Concernant l'indentation je m'excuse mais je n'avais pas pour habitude de le faire.
J'ai appliquer les corrections que vous m'avez fournies mais malheureusement je fais face encore à des problèmes.
Pour la macro 1 je n'arrive pas a faire en sorte, comme vous l'avez dis, que ma variable de début (le département rentré) ne passe qu'a travers une chaîne de conditions.
Pour ma macro2, c'est encore mes fonctions pourtant simples qui peche pour des raisons que j'ignore.
Enfin pour ma macro3 j'observe une erreur d'incompatibilité de type dont je n'arrive pas à me débarrasser.
Merci pour vos réponses!!!
Bonsoir,
Pour y voir clair j'ai repris ton fichier ce matin et commencé à le modifier dans le sens que j'avais indiqué...
Un Userform permettant de choisir le secteur dans une liste simplifie grandement les choses, en le faisant appeler par une fonction (laquelle est appelée par la macro à la place de l'InputBox), on fait renvoyer directement le numéro de colonne par la fonction. Et au lieu de fournir le secteur à la fonction de recherche, on lui fournit la colonne, qu'elle n'a donc plus à définir, ce qui la simplifie encore...
Mais le premier essai que j'ai fait (Agriculture) ma fait sortir le Cantal. Très bien ! Sauf qu'en regardant la base de donnée, on se rend compte que deux autres départements ont la même valeur : Dordogne et Gers. Le Cantal sort parce qu'il précède dans l'ordre alphabétique...
Il faudra donc modifier me semble-t-il pour pouvoir le cas échéant fournir plusieurs résultats !
Devant m'absenter, je n'ai pas eu le temps de regarder de près les deux autres macros. Je ne sais donc pas encore pourquoi elles dysfonctionnent. Mais la 3e me paraît avoir quelques ressemblances avec la 1re, en plus simple dès lors que l'on fera choisir le département dans une liste (ce qui t'évitera les problèmes que tu t'es posés avec la Corse). Pour la 2e (où on retrouve le choix du département), ce devrait être encore plus simple car c'est une simple lecture de ta base, et je pense que tu n'as besoin d'aucune fonction pour cela...
Je regarde demain et te ferai passer le tout...
Cordialement.
Bonjour,
Suivi d'étape...
Comme pour les autres macro il y aura un département à sélectionner, que département ou secteur c'est toujours un choix dans une liste, que l'on ne va pas multiplier les userforms pour des opérations similaires... J'ai donc commencé par réadapter le Userform fabriqué hier ainsi que la fonction d'appel pour les faire répondre aux besoins... Il aurait été mieux de le penser dès le départ plutôt que d'avoir à modifier... Cela ne fait qu'illustrer le temps qu'on perd quand on n'a pas assez pensé avant !
Pour ta macro2, l'idée de monter un tableau était intéressante, cependant à la fin, en affectant la plage au tableau tu ne fais que détruire ton tableau, sans rien affecter !
Cordialement.
Pour suivre avec ta macro3, une expression telle :
Range("Cells(26, G).Value: Cells(26, K).Value")souffre d'au moins 3 erreurs de syntaxe !
1) Ce que tu mets entre guillemets est toujours du texte, qui sera lu tel quel, sans aucune interprétation. Pour renvoyer une plage en utilisant la propriété Range, il faut lui fournir en index une référence de plage, que tu mets alors entre guillemets : Range("G26:K26") par exemple, mais ce que tu as mis entre guillemets ne pourra jamais être interprété comme référence de plage...
2) Range et Cells sont des propriétés qui renvoient un objet Range (et ce ne sont pas les seules: Rows, Columns, Areas en sont également). L'utilisation conjointe de Range et Cells pour définir une plage s'articule selon une syntaxe :
Range(cellule supérieure gauche, cellule inférieure droite)Dans ton cas la 1re cellule est : Cells(26, "G") et la 2e : Cells(26, "K")
Sans guillemets G et K ne sont plus des références, mais des variables non déclarées, non initialisées, de valeur 0 donc, et VBA aura du mal à trouver la colonne 0 de la feuille active !
En outre, la syntaxe officielle de Cells est : Cells(numéro de ligne, numéro de colonne). Si cela fonctionne en substituant la lettre de colonne au numéro (encore que parfois pas...), ce que je regrette profondément (
3) Si tu ajoutes Cells(xxx).Value, ce ne sera plus la référence de la cellule qui sera prise en compte pour définir la plage mais sa valeur... que VBA ne parviendra naturellement pas à interpréter.
Cordialement.
merci beaucoup pour tes reponses!!
Attaquons donc la reconstruction...
D'abord pour homogénéiser, la plage de consignation des résultats de tes macros, la 1 et la 3 occupant A2 et B3 (B3 mieux que B2, car cela permet à l'inscription en A2 d'apparaître...), la 2 occupant 2 lignes sur 10 colonnes, prendra place en B2:K3, les cellules étant mises en saut de ligne automatique et le format de cellule mis en % pour celles devant accueillir des %.
A chaque démarrage de macro on pourra ainsi appeler une procédure unique effaçant la recherche antérieure :
Sub Effacer()
Worksheets("DEP").Range("A2:K3").ClearContents
End SubPas de problème jusque là je pense !
Autre mesure structurelle : on va nommer la première colonne de la Base : Dept. On la nomme en fixe, de A6 à A101, parce qu'elle ne va pas s'étendre.
En écrivant dans le code [Dept] (la mise entre crochets est utilisée pour indiquée une référence en notation compacte, dès qu'il en rencontre une VBA l'évalue, et dans ce cas renverra l'objet Range correspondant à la plage A6:A101 de la feuille DEP).
[A6:A101] représente également une notation compacte de référence... mais non qualifiée (il y a une plage A6:A101 sur toutes les feuilles de tous les classeurs), alors que la précédente est parfaitement qualifiée (le nom est unique dans le classeur !)
Avantage de l'utilisation d'un nom : on n'a plus besoin de se référer à la feuille, le nom suffit, on n'a plus besoin de chercher le nombre de lignes, [Dept].Rows.Count le fournira, et plus de calcul à faire sur le numéro de ligne, la plage commençant en A6, cette ligne (ligne 6 de la feuille) est et restera la ligne 1 de la plage.
Pourquoi ne nommer qu'une colonne ? Parce que cela suffit à dimensionner la base en nombre de ligne, et permettre d'atteindre n'importe quelle autre colonne : [Dept].Offset(, 1) suffira à cibler la colonne voisine des noms de départements, de même que [Dept].Cells(x, y) pointera la cellule de la ligne x et de la colonne y (x et y étant comptés à partir de la plage débutant en A6), on peut donc atteindre en adressage relatif n'importe qu'elle cellule de la base (et si besoin, hors de la base...)
Cet élément permet à lui seul une simplification conséquente du code à développer...
Autre élément dont j'ai déjà parlé, la mise en place d'un Userform pour choisir le Département (macro2 et 3) ou le secteur d'activité (macro1) dans une liste déroulante.
Userform simple, qui se présente ainsi :
La ComboBox accueillera une liste soit des départements, soit des secteurs d'activité. On le voit, on a privilégié les inscriptions relatives aux départements (utilisation 2 fois sur 3 actuellement...) mises en ainsi en valeur par défaut.
Ces valeurs seront modifiées par la procédure appelante dans le cas où c'est le secteur d'activité qui sera à sélectionner (mais plutôt que d'avoir à initialiser les inscriptions dans tous les cas, on n'aura à le faire que dans le cas où ce n'est pas la valeur par défaut... Je le dis toujours, il n'y a jamais de petite économie et chaque fois qu'on peut en faire une il faut le faire !
Le code du Userform (à voir dans le module du Userform) est assez réduit également :
Le Userform doit permettre à l'utilisateur de choisir un élément dans une liste, choix que la procédure appelante doit pouvoir récupérer. Le choix étant fait dans la ComboBox, l'élément choisi de la liste aura pour rang dans la liste la valeur de la propriété ListIndex de la Combo +1 (numérotation à partir de 0 dans les ComboBox et ListBox).
Il suffira donc de récupérer ce rang, ce qu'on va faciliter en l'affectant à une variable publique au niveau Userform dont la valeur pourra être récupérée par la proc. appelante (on aurait pu s'en passer, la proc. récupérant alors directement la valeur du ListIndex, mais cela peut être plus clair ainsi, et dans le cas où d'autres développements seraient ajoutés...)
Public Choix As IntegerSi l'utilisateur clique sur OK, la proc. associée affectera la valeur du ListIndex +1 à la variable Choix...
Private Sub cbOK_Click()
If cbxChoix.ListIndex = -1 Then
MsgBox "Choisir un " & Me.Tag & " !", vbExclamation, "Choix de " & Me.Tag
Exit Sub
End If
Choix = cbxChoix.ListIndex + 1
Me.Hide
End SubComme on voit, on teste d'abord si l'utilisateur a fait un choix !
Tag est une propriété du Userform (tous les contrôles disposent aussi de leur Tag) susceptible d'accueillir une valeur de type String. Ici on a mis par défaut la valeur : département, à laquelle on pourra le cas échéant substituer la valeur secteur d'activité en appelant le Userform, ce qui est utilisé pour préciser à l'utilisateur la nature de ce qu'il a à choisir...
Si l'utilisateur annule :
Private Sub cbAnnul_Click()
Choix = 0
Me.Hide
End Subon affecte 0 à la variable. Dans les deux cas (OK ou Annuler) on masque le Userform et c'est la procédure appelante qui prendra le relais pour recueillir la réponse...
Une dernière précaution, au cas où l'utilisateur cliquerait sur la croix de fermeture :
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = vbFormControlMenu Then
Cancel = True
cbAnnul_Click
End If
End Subon annule cette requête de fermeture et on renvoie sur la procédure d'annulation...
La procédure appelante est en fait une procédure Function, qui sera elle-même appelée par les macros 1, 2 et 3 pour qu'elle leur renvoie selon le cas le numéro de ligne du département dans les données de la base ou le numéro de colonne du secteur d'activité... Elle sera appelée en luis passant comme argument le numéro de la macro appelante, ce qui lui permettra d'interpréter correctement la demande...
Function ChoixSectDpt(m As Integer) As Integer
Dim k%, LstS
With UserForm1
Select Case m
Case 1
LstS = WorksheetFunction.Transpose(Worksheets("DEP").Range("G5:K5"))
.Caption = "Secteur d'activité recherché"
.lbInfo.Caption = "Sélectionner le secteur d'activité recherché ci-dessous :"
.Tag = "secteur d'activité"
Case 2, 3
LstS = [Dept].Offset(, 1).Value
End Select
.cbxChoix.List = LstS
.Show
k = .Choix + IIf(m = 1, 6, 0)
End With
Unload UserForm1
ChoixSectDpt = k
End FunctionElle initialise le Userform en fonction de la macro demandant le choix : la liste à affecter à la Combo (par l'intermédiaire d'une variable tableau, initialisée avec les secteurs d'activité (cas 1) ou les départements (cas2 et 3), et pour le cas 1 modification des diverses inscriptions qui ne correspondent aux valeurs par défaut...
A l'affichage du Userform, ce dernier prend la main. Lorsqu'il sera masqué, l'exécution se poursuivra en récupérant dans une variable k le choix effectuée (valeur de la variable Choix du Userform).
Pour les secteurs d'activité, elle va recueillir une valeur de 1 à 5, or les colonnes desdits secteurs vont de 7 à 11, elle opèrera donc une correction de +6 au numéro recueilli. Par contre, pour les départements, le numéro recueilli correspondra exactement au numéro de ligne de la plage B6:B101 (donc correction =0).
Elle renvoie donc la valeur cherchée, après avoir déchargé le Userform.
Il ne reste plus qu'à passer aux 3 macros...
à suivre...
Commençons par la Macro1 :
Sub Macro1()
Dim Sect%, Z$, SA$
Effacer
Sect = ChoixSectDpt(1)
If Sect = 0 Then Exit Sub
Z = MeilleurDept(Sect)
With Worksheets("DEP")
SA = .Cells(5, Sect)
.Range("A2") = "Meilleur département, secteur " & SA & " :"
.Range("B3") = Z
End With
MsgBox "Meilleur département pour le secteur " & SA & " :" & Chr(10) & Z, _
vbInformation, "Meilleur département"
End SubOn commence par effacer la zone de résultats (ce que feront également les 2 autres macros).
On questionne l'utilisateur sur son choix (ici secteur d'activité) qu'on recueille dans la variable Sect. [Les deux autres macros feront de même, le choix portant sur le département, mais appel à la fonction vu précédemment, sauf que chaque macro lui communique son numéro permettant de l'identifier).
Elle recueille ensuite dans la variable Z (type String) le résultat de la recherche effectuée par une fonction : MeilleurDept, qu'elle appelle en lui passant le secteur d'activité recherché (Sect =numéro de colonne du secteur), que nous allons examiner à la suite.
Disposant de tous les éléments, elle peut passer à l'affectation des résultats : elle recueille encore dans une variable SA (type String) le nom du secteur en allant le chercher dans la ligne d'en-tête, puis inscrit dans A2 l'objet de la recherche et dans B3 le résultat.
Elle affiche également un message communiquant le même résultat.
Rien de particulier !
Function MeilleurDept(S As Integer) As String
Dim a, b, i%, md$
With [Dept]
For i = 1 To .Rows.Count
If a < .Cells(i, S) Then
a = .Cells(i, S): b = i
ElseIf a = .Cells(i, S) Then
b = b & ";" & i
End If
Next i
If InStr(1, b, ";") > 0 Then
b = Split(b, ";")
For i = 0 To UBound(b)
md = md & Chr(10) & .Cells(CInt(b(i)), 2)
Next i
MeilleurDept = Replace(md, Chr(10), "", 1, 1)
Else
MeilleurDept = .Cells(b, 2)
End If
End With
End FunctionJ'avais donné une version très simplifiée de cette procédure par rapport à la procédure visant initialement le même objet. Ici, elle s'est à nouveau un peu plus étoffée dans la mesure où il fallait prendre en compte les cas d'égalité impliquant plusieurs réponses simultanées.
La fonction est appelée avec le numéro de la colonne dans laquelle elle doit opérer. Elle va donc parcourir les lignes de données pour comparer les éléments de cette colonne.
La variable a étant vide au départ, elle lui affectera la valeur trouvée en première ligne, nécessairement plus grande ! Puis chaque fois qu'elle rencontre une valeur supérieure à celle recueilli en a, elle la substituera pour poursuivre la comparaison.
Parallèlement elle affecte à b le numéro de ligne correspondant à la valeur mise en a...
S'en tenir là escamotait les cas d'égalité de résultats pouvant survenir : si donc ce test est infructueux (la valeur de la ligne n'est pas supérieure à a), on fait alors un test d'égalité, car si le test est positif cela veut dire que si la valeur de a sera en définitive la valeur supérieure trouvée, il y a d'autres départements que le premier recensé qui seront à liste comme résultat !
Donc en cas d'égalité, on ajoute au numéro de ligne déjà en b qu'on conserve le nouveau numéro de ligne en le séparant du précédent par un point-virgule. La variable b qu'on a conservée à cette fin de type Variant, aura une valeur numérique de type Integer tant que l'on n'aura qu'un seul département éligible au résultat final, et prendra une valeur de type String dès lors que d'autres départements éligibles viendront s'ajouter au premier...
Une fois la colonne entièrement parcourue, on commencera par tester b : si son contenu contient le caractère ";" c'est qu'on a un résultat multiple.
Pour le recueillir, on splitte alors b sur ce caractère, ce qui le transforme en tableau des numéros de lignes qui ont été cumulés. En parcourant ce tableau on va composer la réponse dans une variable md (String) en y concaténant les noms des départements séparés par un caractère saut de ligne (Chr(10)).
Le résultat renvoyé à la macro sera cette chaîne dont on aura ôté le premier Chr(10) superflu. Valeur qui, affectée à une cellule dont le saut de ligne automatique est activé, fera apparaître les départements en liste...
Si on est dans le cas standard d'un seul résultat, la fonction renverra simplement le nom du département en le prélevant sur la ligne indiquée par la variable b (alors numérique).
à suivre...
La Macro2 est pour sa part destinée à fournir des informations sur un département choisi, informations réparties sur 10 colonnes, prélevées directement sur la ligne concernant le département dans la base, ou calculées à partir des données de cette ligne.
Le résultat fourni pas la macro comporte 2 lignes : une ligne d'en-tête et celle des résultats proprement dits.
La composition de ces deux lignes étant fort différente, il apparaît préférable de les dissocier.
Une fois les éléments préparatoires lancés (effacement, choix du département, test qu'un département est choisi),
on compose facilement la ligne d'en-tête en appliquant la fonction Split à une chaîne concaténant ces libellés avec un caractère séparateur permettant d'obtenir un tableau unidimensionnel des libellés d'en-tête.
On composera ensuite la ligne de résultat en utilisant un tableau à 10 élément (0 à 9) : Tbl.
Pour opérer on dispose du numéro de ligne correspondant au département recueilli dans la variable dpt.
On opèrera commodément en mettant sous bloc With la première cellule de la ligne :
With [Dept].Cells(dpt, 1)En se référant à cette cellule, la ligne sur laquelle on opère devient la ligne 1. La cellule mémorisée étant en A, les colonnes conservent leur numéro.
Les éléments fixe sont les éléments 0 et 4 du tableau, prélevés sur les colonnes 2 et 5 de la ligne.
Les éléments 2 et 3 du tableau sont constitués par le rapport des valeurs des colonnes 3 et 4 à la valeur recueillie en élément 4 [et sans multiplier le résultat par 100
Les éléments 5 à 9 du tableau sont constitués par les valeurs des colonnes 7 à 11... mais comme ces colonnes contiennent en fait des valeurs "brutes" correspondant à la valeur réelle multipliée par 100, il convient de les calculer en divisant par 100 ! (voir ci-après). Ce qu'on fait pareillement au moyen d'une boucle.
L'élément 1 du tableau quant à lui traduit par une mention littérale la valeur de la colonne 6, ce qu'on fait en testant si cette valeur est positive ou négative, et sans omettre le cas où elle est nulle !
Sub Macro2()
Dim Tbl(9), Libl, dpt%, i%
Effacer
dpt = ChoixSectDpt(2)
If dpt = 0 Then Exit Sub
Libl = Split("Département;Etat emploi;Emploi salarié;Emploi non salarié;Emploi total (milliers);" _
& "Agriculture;Industrie;Construction;Tertiaire marchand;Tertiaire non marchand", ";")
With [Dept].Cells(dpt, 1)
Tbl(0) = .Cells(1, 2): Tbl(4) = .Cells(1, 5)
For i = 2 To 3
Tbl(i) = .Cells(1, i + 1) / Tbl(4)
Next i
For i = 5 To 9
Tbl(i) = .Cells(1, i + 2) / 100
Next i
Tbl(1) = IIf(.Cells(1, 6) < 0, "Chômage accru", IIf(.Cells(1, 6) > 0, "Croissance", _
"Stabilité"))
End With
With Worksheets("DEP")
.Range("B2:K2").Value = Libl
.Range("B3:K3").Value = Tbl
End With
End SubUne fois fait tout ceci, l'affectation des résultats se réalise avec deux lignes d'affection : à chaque plage cible son tableau...
On le voit, il n'était pas du tout nécessaire de mobiliser une batterie de fonctions pour composer le résultat voulu.
Je reviens sur un point qui témoigne d'une incompréhension de ce qu'est un pourcentage, et comment il apparaît dans Excel.
Lorsqu'on dit ou écrit 3%, la valeur de cette expression est : 3/100, soit : 0,03 !
Une cellule Excel dont le format est Pourcentage et qui contient 0,03 affichera : 3%.
Lorsqu'on calcule le taux d'emploi salarié par rapport au total, la valeur de ce taux ou pourcentage est simplement le rapport de ces deux valeurs. Ce rapport dit simplement ce que représente l'emploi salarié si le total vaut 1. Ce qui permet de ramener à une même échelle des grandeur différentes pour pouvoir les comparer.
C'est le format de cellule qui fera apparaître cette valeur comme multipliée par 100 en l'assortissant du symbole %, sans aucunement changer la valeur.
Il se trouve par ailleurs que les chiffres de la base sont tous insérés dans des cellules au format nombre à une décimale. S'agissant de valeur censées représenter des pourcentages, la valeur des cellules est donc la valeur réelle multipliée par 100. Le mieux aurait été certainement de rectifier la base pour avoir les valeurs réelles et mettre les cellules concernées au format %. A défaut on a rétabli la valeur réelle pour les résultats de recherche et formaté les cellules de résultats en conséquence.
à suivre...
Finissons-en avec la Macro3, qui offre quelque ressemblance avec la Macro1. A partir du choix d'un département on doit renvoyer le secteur d'activité majoritaire.
Du moins, c'est ce qu'on pouvait déduire de mieux du code initial qui, outre des fautes de syntaxe, inversait l'ordre logique des lignes de commande (on initialisait une variable par exemple après l'avoir utilisée...)
J'y reviendrai ensuite car j'ai quelques doutes du fait que les résultats renvoyés par cette macro paraissent dénués d'intérêt...
On procède donc de façon analogue à la Macro1, mais sans passer par une fonction :
Sub Macro3()
Dim dpt%, SA$, Dp$, i%, b%, a, Sact
Effacer
dpt = ChoixSectDpt(3)
If dpt = 0 Then Exit Sub
Sact = Split("Agriculture;Industrie;Construction;Tertiaire marchand;Tertiaire non marchand", ";")
With [Dept]
Dp = .Cells(dpt, 2)
With .Cells(dpt, 7).Resize(, 5)
For i = 1 To 5
If a < .Cells(1, i) Then
a = .Cells(1, i): b = i - 1
End If
Next i
End With
End With
SA = Sact(b)
With Worksheets("DEP")
.Range("A2") = "Meilleur secteur d'activité, département " & Dp & " :"
.Range("B3") = SA
End With
MsgBox "Meilleur secteur d'activité pour le département " & Dp & " :" & Chr(10) & SA, _
vbInformation, "Meilleur secteur d'activité"
End SubUne fois le démarrage fait, comme pour les autres, je n'y reviens pas, on dispose du numéro de ligne dans la variable dpt.
On aura besoin du nom du secteur d'activité à renvoyer en résultat, on en fait donc un tableau Sact dans lequel on pourra récupérer le nom cherché.
Pour les besoins d'inscriptions et du message final, on a aussi besoin du nom du département, on le récupère dans la variable Dp.
On entre dans le vif du sujet en ciblant dans un bloc With la plage des secteurs d'activité sur la ligne du département avec With .Cells(dpt, 7).Resize(, 5) faisant déjà référence à [Dept].
Une boucle sur les colonnes de la plage, avec a pour mémoriser la valeur supérieure et b le rang de la colonne (qu'on diminue de 1 pour s'ajuster à notre tableau des secteurs), et on arrive au résultat : on consigne le nom du secteur dans une variable SA et on affecte les résultats en A2 et B3 et produit le message final...
Fort bien !
En bonne logique, le problème d'égalité se poserait comme pour la Macro1, mais j'ai omis de le traiter dans la mesure où cette macro n'apportant aucune information pertinente a tout lieu de devoir être abandonnée, ou bien remplacée par une recherche plus petinente (sans omettre le fait que l'interprétation du rôle qu'elle devait jouer était erroné dès le départ).
La révision est bouclée. A suivre le fichier et dernières recommandations...
Le fichier : j'ai ajouté 3 boutons pour lancer les macros. Secondaire, mais c'est plus convivial.
J'ai surtout fait un peu de nettoyage...
Tu noteras que toutes les procédures indiquées sont dans Module1 (à l'exception de celles du Userform, naturellement dans le module dédié à l'objet). Elles y tiennent très bien et il y a encore de la place pour en mettre beaucoup beaucoup plus !
Pour respecter les règles, qui ne sont pas que purement conventionnelles, le code placé dans un module s'organise de la façon suivante : les déclarations de niveau module (s'il y en a), puis les procédures Function, puis les procédures Sub (je passe sur les critères pouvant être utilisés pour ordonnancer les éléments de chacune de ces catégories...)
Le code est indenté systématiquement selon les mêmes règles... Tu devrais te rendre compte à l'usage que l'on voit plus vite de quoi il retourne en le lisant...
Cordialement.