[VBA] Alimenter ListBox multicolonnes à partir d'un tableau à 1 dimension
- Messages
- 1'025
- Excel
- 2016 FR // 365
- Inscrit
- 19/04/2019
- Emploi
- Étudiant en 5e année d'école d'Ingénieur
Bonjour le forum !
Je bloque depuis quelques jours sur un sujet que je n'arrive pas à résoudre...
Mon sujet : Je dois alimenter une ListBox multicolonnes via un tableau nommé de datas. Les données affichées sont auparavant filtrées afin de n'obtenir que des données précises et en plus de ça, je n'affiche que certaines colonnes dans la ListBox. Cette opération, je peux y arriver sans trop de difficulté à l'aide de boucles, mais ayant une grosse base et ayant un esprit d'allégement du code et de son temps d'exécution, j'ai choisi la voie "moins facile" que voici :
'Importe données filtrées puis sélectionne les colonnes désirées
With Range("Tableau1")
BD = Filter(.Parent.Evaluate("transpose(if(" & .Columns(Range("Tableau1[Nombre]").Column).Address & _
">50,row(1:" & .Rows.Count & "),char(2)))"), Chr(2), 0)
If Len(Join(BD)) = 0 Then Exit Sub 'Si aucune donnée, ne charge rien dans la ListBox1
BD = Application.Index(.Value, Application.Transpose(BD), ColVisu)
End With
'Remplis la ListBox
Me.ListBox1.List = BD
Ce code fonctionne à merveille ! Mon problème arrive lorsque je n'ai qu'une ligne de résultat après le filtrage. Si dans mon code exemple, au lieu de mettre ">50" je mets "<30", il n'y a qu'un résultat dans mon tableau et celui-ci ne s'affiche pas sur une ligne dans ma ListBox (ce que je désire) mais sur la première colonne...
En effectuant des tests, cela vient du fait que ma variable tableau est à une 1 dimension. J'ai l'impression que mon problème n'est pas si difficile, mais impossible d'arriver à le résoudre !
L'un d'entre vous aurait-il une idée ?
Le fichier :
Merci et bonne soirée,
Baboutz
Salut Baboutz,
une solution :
Private Sub UserForm_Initialize()
'Déclaration des variables
Dim ColVisu, LargeurCol, BD
Dim j As Byte
'Définition des colonnes à afficher
ColVisu = Array(Range("Tableau1[Nombre]").Column, _
Range("Tableau1[Valide]").Column, _
Range("Tableau1[Date]").Column)
'Définition de la longueur des colonnes
LargeurCol = Array(70, 70, 70)
'Assemblage des colonnes voulues dans un array
Me.ListBox1.ColumnCount = UBound(ColVisu) + 1
Me.ListBox1.ColumnWidths = Join(LargeurCol, ";")
'Importe données filtrées puis sélectionne les colonnes désirées
With Range("Tableau1")
BD = Filter(.Parent.Evaluate("transpose(if(" & .Columns(Range("Tableau1[Nombre]").Column).Address & _
"<30,row(1:" & .Rows.Count & "),char(2)))"), Chr(2), 0)
If Len(Join(BD)) = 0 Then Exit Sub 'Si aucune donnée, ne charge rien dans la ListBox1
BD = Application.Index(.Value, Application.Transpose(BD), ColVisu)
If Len(Join(BD)) > 1 Then
Me.ListBox1.List = BD
Else
j = 0
For Each valeur In BD
Me.ListBox1.AddItem
Me.ListBox1.List(0, j) = valeur
j = j + 1
Next valeur
End If
End With
End Sub
- Messages
- 3'581
- Excel
- 2013, 2019, 365
- Inscrit
- 11/04/2020
- Emploi
- Formateur bureautique, dvpt fichiers
Hello tout le monde !
Certainement moins optimisé, mais j'aurais fait ça de mon côté :
Private Sub UserForm_Initialize()
'Déclaration des variables
Dim ColVisu, LargeurCol, BD
Dim i as byte, j As Byte, z As Byte, x as byte, compteur As Long
'Définition de la longueur des colonnes
LargeurCol = Array(70, 70, 70)
'Assemblage des colonnes voulues dans un array
Me.ListBox1.ColumnCount = 3
Me.ListBox1.ColumnWidths = Join(LargeurCol, ";")
compteur = 0
For Each cell In Feuil1.ListObjects("Tableau1").ListColumns("Nombre").DataBodyRange
If cell.Value > 50 Then compteur = compteur + 1
Next
If compteur = 0 Then Exit Sub
x = 0
For i = 2 To Feuil1.ListObjects("Tableau1").ListColumns("Nombre").DataBodyRange.Rows.Count
'Ajoute une ligne et insère une donnée dans la colonne de gauche
If Feuil1.Cells(i, 1).Value > 50 Then
ListBox1.AddItem
'Ajoute des données dans les colonnes de droite
Z = 1
For j = 0 To 2
ListBox1.List(x, j) = Feuil1.Cells(i, Z)
Z = Z + 2
Next
x = x + 1
Else: End If
Next i
End Sub
Je suis vraiment ouvert à ce qu'on me dise pourquoi telle ou telle chose est mieux ou moins bien qu'une autre !
Hello JoyeuxNoel,
Perso j'aime bien ta version. On a ci-dessous 2 styles différents, la manipulation par les boucles & par les formules.
Moi je suis + comme toi, je préfère passer par des boucles.
En revanche ici, là où ça pèche un peu dans ton approche c'est dans ce choix :
ListBox1.AddItem
cette méthode est beaucoup + lente à charger les données dans la listbox que :
Me.ListBox1.List = BD
Moi je l'ai utilisé car via :
If Len(Join(BD)) = 0 Then Exit Sub 'Si aucune donnée, ne charge rien dans la ListBox1
BD = Application.Index(.Value, Application.Transpose(BD), ColVisu)
If Len(Join(BD)) > 1 Then
Me.ListBox1.List = BD
je sais que j'ai qu'une ligne à charger, je peux donc utiliser additem sans crainte de lenteur.
Voila
Bonne soirée à tous.
- Messages
- 1'025
- Excel
- 2016 FR // 365
- Inscrit
- 19/04/2019
- Emploi
- Étudiant en 5e année d'école d'Ingénieur
Bonjour à vous deux,
Merci pour vos participations !
Je me suis tellement compliqué la tête à chercher la solution autour de la variable tableau que j'ai oublié de prendre du recul
J'aurai préféré avoir une solution plus "courte" mais je ne pense pas qu'elle existe, je me contenterai de cela.
@JoyeuxNoel
En soit les boucles c'est bien, mais quand tu as beaucoup de données, ça peut ralentir ta macro. De plus que là, tu boucles directement sur les cellules de ta feuille, il est préférable de boucler sur un array.
Après, je fais le difficile aussi, mais j'aime optimiser au max mes codes
Merci encore et bonne journée,
Baboutz
- Messages
- 1'025
- Excel
- 2016 FR // 365
- Inscrit
- 19/04/2019
- Emploi
- Étudiant en 5e année d'école d'Ingénieur
Erratum: Ta proposition Rag02700 ne fonctionne malheureusement pas, Len(Join(BD)) > 1
ne permet pas de traiter lorsqu'il n'y a qu'un résultat...
Bonjour à tous,
Si j'ai bien compris, voici une proposition avec un code minimaliste via sql (la borne 50 pourrait être une variable issue de qqpart)
Private Sub UserForm_Initialize()
Me.ListBox1.List = T_List(50)
Me.ListBox1.ColumnCount = UBound(Me.ListBox1.List, 2) + 1
End Sub
Pierre
- Messages
- 1'025
- Excel
- 2016 FR // 365
- Inscrit
- 19/04/2019
- Emploi
- Étudiant en 5e année d'école d'Ingénieur
Re,
Je viens de réussir à trouver la solution un peu au hasard...
Il suffit d'utiliser la propriété .Column
au lieu de .List
!!! Et pour gérer le cas de plusieurs résultats, on ajoute un Application.Transpose()
avant !
Ce qui nous donne :
Private Sub UserForm_Initialize()
'Déclaration des variables
Dim ColVisu, LargeurCol, BD
'Définition des colonnes à afficher
ColVisu = Array(Range("Tableau1[Nombre]").Column, _
Range("Tableau1[Valide]").Column, _
Range("Tableau1[Date]").Column)
'Définition de la longueur des colonnes
LargeurCol = Array(70, 70, 70)
'Assemblage des colonnes voulues dans un array
Me.ListBox1.ColumnCount = UBound(ColVisu) + 1
Me.ListBox1.ColumnWidths = Join(LargeurCol, ";")
'Importe données filtrées puis sélectionne les colonnes désirées
With Range("Tableau1")
BD = Filter(.Parent.Evaluate("transpose(if(" & .Columns(Range("Tableau1[Nombre]").Column).Address & _
"<30,row(1:" & .Rows.Count & "),char(2)))"), Chr(2), 0)
If Len(Join(BD)) = 0 Then Exit Sub 'Si aucune donnée, ne charge rien dans la ListBox1
BD = Application.Index(.Value, Application.Transpose(BD), ColVisu)
BD = Application.Transpose(BD)
End With
'Remplis la ListBox
Me.ListBox1.Column = BD
End Sub
Le fichier :
Merci encore et bonne journée,
Baboutz
- Messages
- 1'025
- Excel
- 2016 FR // 365
- Inscrit
- 19/04/2019
- Emploi
- Étudiant en 5e année d'école d'Ingénieur
Salut Pierre,
Très belle solution également !
Je maîtrise très mal encore les solutions SQL depuis VBA, il faudrait que je m'y penche car ça a l'air assez puissant et beaucoup plus modulable !
Très puissant (exemple simple : Facebook est basé sur du Sql) et très rapide à mettre en œuvre.
LA Source => https://sql.sh/
- Messages
- 3'581
- Excel
- 2013, 2019, 365
- Inscrit
- 11/04/2020
- Emploi
- Formateur bureautique, dvpt fichiers
Bonjour tout le monde !
@Baboutz, je suis bien d'accord sur le fait que chercher dans un array est plus rapide. Mais comme je sais que tu sais le faire, et que j'avais la flemme, tu vois ...
@Rag, merci pour ce retour !
Je ne savais pas que c'était plus lent. Je n'ai jamais eu assez de données à charger pour me rendre compte de ceci, mais c'est bon à savoir !