Liste déroulante ordre inverse
Bonjour,
Je souhaiterai avoir une liste déroulante qui affiche la liste mais en ordre inverse de la colonne avec les dernières données affichée en premier. C'est une liste qui a aussi la nécessité d'être dynamique dans le sens où des données seront rajoutées au fur et à mesure dans la colonne. J'ai trouvé le moyen de faire ça en rajoutant une colonne à mon tableau et en affichant les valeurs en ordre inverse mais je préférerai faire ça sans rajouter de colonne à la table ou plutôt avoir une nouvelle colonne mais ailleurs dans la feuille. Avez vous des idées?
Merci !
Bonjour,
Merci de joindre un fichier, ce sera plus facile de proposer une solution correspondant exactement à ton problème.
Voilà un fichier tout simple correspondant à mon problème
Bonjour,
Essayer :
Private Sub Worksheet_Change(ByVal Target As Range)
Dim aa, bb(), i%, n%
If Not Intersect(Target, [Tableau1].Columns(1)) Is Nothing Then
aa = [Tableau1].Resize(, 1)
n = UBound(aa)
ReDim bb(1 To n)
For i = 1 To n
bb(n + 1 - i) = aa(i, 1)
Next i
With [Tableau1].Offset(, 1).Resize(, 1).Validation
.Delete
.Add xlValidateList, , , Join(bb, ",")
End With
End If
End SubA placer dans le module de la feuille.
Cordialement.
Bonjour,
je ne suis pas sur d'avoir tout compris.
Il me semble qu'il suffit juste de sélectionne l'option "Trier du plus récent au plus ancien"
sur ton onglet de sélection de liste ?
oops avais pas vu réponse .. rebonjour MFerrand
Merci MFerrand, ça doit probablement fonctionner seulement j'ai du mal à comprendre le code et donc j'ai du mal à l'adapter à mon fichier, pouvez vous commenter votre code?
De plus je ne peux pas ouvrir la pièce jointe que vous avez mis en copie, Excel me dit que le fichier est endommagé et qu'il doit le réparer. A la réparation il me supprime le tableau et le code de la Worksheet_Change. J'ai un autre fichier qui a exactement le même problème savez vous d'où ça peut venir?
Merci encore
Bonjour,
J'ai rouvert le fichier et noté le même problème... Ceci dit, récupéré, il refonctionne normalement. Excel ne doit pas supporter les liste de validation longues entrées directement, j'en ai donc fait une version modifiée pour supprimer la validation lors de l'enregistrement du classeur, la (re)création de la liste est sortie de la Change, et elle est lancée par la Change en cas de modification et également à l'ouverture du classeur.
Ce qui élimine le problème. Maintenant, si tu atteins un phase où ça saturerait sans attendre la réouverture du fichier, il faudra alors passer par une plage...
Cordialement.
Explications vont venir, c'est fort simple, je met d'abord le fichier.
Re,
On en vient aux explications... réfléchissons un peu, tu prends une liste d'éléments, tu veux la mettre dans l'ordre inverse... replaçons-nous à la maternelle, tu as devant toi des gomettes alignées qui forment une colonne, on te demande de les replacer dans l'ordre inverse, la dernière devenant la première, la première devenant la dernière. Que fais-tu ?
Tu vas les replacer dans une nouvelle colonne, tu prends la dernière et tu la places en tête de la nouvelle colonne, puis la suivante en remontant que tu places à la suite, et ainsi jusqu'à ce que tu les aies toutes reclassées.
Avec VBA, on ne fait pas autre chose ! Mettons que tu aies 10 éléments dans une colonne, chacun sur une ligne, le premier sera ligne 1, le dernier ligne 10, les replaçant dans une nouvelle colonne, tu vas mettre le 10 en 1 dans la nouvelle, le 9 en 2, le 8 en 3... le 2 en 9 et le 1 en 10.
Avec 10 tu peux facilement faire le calcul mental : la nouvelle position se déduit du nombre d'éléments + 1 - l'ancienne position.
On a 10 éléments :
anc. = 10 => nouv. = 10 + 1 - 10 = 1
anc. = 9 => nouv. = 10 + 1 -9 = 2
anc.= 1 => nouv. = 10 + 1 - 1 = 10
C'est ce qu'on fait dans la procédure, on ne le matérialise pas directement sur la feuille tant qu'on n'a pas fini, on opère en mémoire avec ce que l'on nomme tableaux, que tu ne vois pas tant qu'on ne l'appose pas sur une feuille, et ici on ne le met pas sur feuille mais dans la validation, tu ne le vois donc que par la liste de validation qui apparaît dans les cellules.
aa = [Tableau1].Resize(, 1)Tableau1 est ton tableau Excel à 2 colonnes, on le redimensionne sur une seule colonne, il ne comprend donc plus que la première colonne. On en affecte les valeurs à une variable de type Variant, ce qui produit un tableau à 2 dimensions de base 1 (indice ligne allant de 1 au nombre de lignes total, indice colonne allant de 1 à 1). Ce tableau a le même contenu que la plage constituée par la première colonne du Tableau1 mais on l'a sortie d'Excel pour travailler (plus vite) sur ce tableau (virtuel).
n = UBound(aa)
ReDim bb(1 To n)Ligne suivante, on initialise la variable Integer n au nombre de lignes de notre tableau initial. Les lignes partant de 1, l'indice maximal du tableau fourni par UBound est identique au nombre de lignes.
Ligne en dessous, on dimensionne une variable tableau, déclarée comme tableau dynamique (sans dimensionnement préalable) sur le nombre de lignes de notre premier tableau, de 1 à n.
Celui-ci va nous servir à reclasser nos éléments, il doit donc pouvoir accueillir le même nombre d'éléments que ceux que nous avons à reclasser. Le précédent s'est dimensionné automatiquement sur la plage qu'on a prélevée, celui-ci on le dimensionne avant utilisation pour qu'il corresponde aux lignes de la plage. Le précédent a 2 dimensions, même si la seconde ne prend qu'un seul indice, parce qu'il s'est calqué sur la plage. Le nouveau n'en a qu'une, car nous allons l'utiliser comme simple liste pour la validation, ce qu'une 2e dimension ne nous permettrait pas de faire.
For i = 1 To n
bb(n + 1 - i) = aa(i, 1)
Next iEtape suivante, on remplit notre tableau vide avec les éléments du tableau issu de la plage, selon la règle définie au début de ce post... On parcourt les lignes du tableau-plage en boucle, i représente ainsi l'ancienne position de chaque élément, de 1 à n. Avec i et n on calcule la nouvelle position dans le nouveau tableau, et on affecte l'élément à cette nouvelle position calculée.
With [Tableau1].Offset(, 1).Resize(, 1).Validation
.Delete
.Add xlValidateList, , , Join(bb, ",")
End WithPour finir, on revient sur notre feuille, dans notre Tableau Excel : cette fois on le décale (Offset) d'une colonne, pour atteindre la 2e colonne dans laquelle on veut placer notre liste, et on le redimensionne sur une colonne... et à partir de cette plage on accède au composant Validation d'Excel que l'on veut paramétrer pour qu'une liste soit affichée dans les cellules de la plage.
On définit ainsi un objet Validation concernant la plage ciblée, on le place sous instruction With... End With car l'on a plusieurs opération à réaliser sur cet objet. Cette instruction a pour effet de faire placer la référence de l'objet en mémoire par VBA qui peut ainsi l'atteindre plus rapidement. Et pour référer à l'objet à l'intérieur de l'instruction, on n'a plus à le répéter, un point placé devant l'expression permet d'y référer. Et pour définir notre liste : texte reprenant les libellés séparés par des virgules
On a 2 opérations à faire sur cet objet : supprimer l'ancienne liste éventuelle, et affecter la nouvelle.
La première : suppression n'exige pas d'entrer dans les détail, on supprime et c'est tout.
La seconde exige que l'on définisse le type de validation (sur liste dans la cellule) et que l'on fournisse la liste, soit les paramètres Type et Formula1 de la méthode. Les autres paramètres sont soit inutiles pour une liste (Operator, Formula2), soit on les laisse à leur valeur par défaut (AlertStyle), on n'a donc nul besoin de s'en préoccuper.
Ceci parce que contrairement à l'enregistreur, on réfléchit pour ne pas écrire du code totalement inutile. Et contrairement à l'enregistreur encore, on passe les arguments (paramètres) par position (en respectant la position de chaque paramètre défini dans la méthode, ce qui allège l'écriture et est d'ailleurs la façon normale d'écrire en VBA, les vides entre les virgules indiquent la position de paramètres optionnels que l'on n'utilise pas (le passage par noms ne présente d'intérêt pratique que l'on a de nombreux paramètres et que l'on n'utilise que les derniers... cela évite alors des erreurs dans le nombre de virgules intermédiaires à placer pour bien définir la position).
Ce point formel d'écriture étant vu, on définit la liste de même façon que lorsqu'on la saisit manuellement dans la boîte de dialogue en tapant les libellés séparés par des points-virgule. Opérant en VBA, le séparateur obligatoire à utiliser est la virgule, à partir de notre tableau unidimensionnel on utilise la fonction Join qui permet de constituer une chaîne-texte des éléments du tableau en séparant par un séparateur qu'on indique.
Et voilà. (Je ne donnerai pas autant de détails tout le temps...
Cordialement.
Private Sub Worksheet_Change(ByVal Target As Range) Dim aa, bb(), i%, n% If Not Intersect(Target, [Tableau1].Columns(1)) Is Nothing Then aa = [Tableau1].Resize(, 1) n = UBound(aa) ReDim bb(1 To n) For i = 1 To n bb(n + 1 - i) = aa(i, 1) Next i With [Tableau1].Offset(, 1).Resize(, 1).Validation .Delete .Add xlValidateList, , , Join(bb, ",") End With End If End Sub
Quelle magnifique prose, ne peut-on l'écrire en vers ?
Si si, ce n'est pas caustique, j'admire la façon dont c'est conceptualisé et écrit ! J'en suis encore malheureusement formaté par le premier langage que j'ai touché : le Fortran que tu as dû connaître...
J'ai longtemps hésité sur cette demande originale mais aussi pratique sans doute. Je vais quand même finalisé la méthode à laquelle je pensais mais que j'avais laissée de côté car elle demandait une ou deux lignes de VBA.
Une contribution
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A:A")) Then
Sheets("TCD").PivotTables("TCD1").PivotCache.Refresh
End If
End Sub
Merci à vous ! Surtout à MFerrand pour cette explication très pédagogique !
Bonne continuation...
@Steelson : intéressant !