[VBA] Alimenter ListBox multicolonnes à partir d'un tableau à 1 dimension

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...

image

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 :

21test.xlsm (28.23 Ko)

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

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.

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 Ta solution me convient, merci Rag02700 !
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

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

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 :

19test.xlsm (29.89 Ko)

Merci encore et bonne journée,

Baboutz

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/

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 !

Rechercher des sujets similaires à "vba alimenter listbox multicolonnes partir tableau dimension"