XL 2010 [RESOLU] Listbox et Listobject

cathodique

XLDnaute Barbatruc
Bonjour,

D'habitude pour alimenter une Listbox à partir d'un tableau structuré (ListObject), s'il se nomme Tb, le code suivant était suffisant pour alimenter le listbox
VB:
[Tb].value
En travaillant sur un fichier, je me suis rendu compte que ce code fonctionne si et seulement si, il y a au moins 2 lignes de données.
En effet, si le tableau a une ligne ou non vide le code plante. Je n'arrive pas à contourner ce problème.
Voici le code pour celles et ceux qui n'ouvrent jamais les fichiers joints.
Code:
Option Explicit

Private Sub UserForm_Initialize()
   Dim Tb1 As ListObject, Tb2 As ListObject, Tb3 As ListObject
   With Sheets("feuil1")
      Set Tb1 = .ListObjects("Tjeux1")
      Set Tb2 = .ListObjects("Tjeux2")
      Set Tb3 = .ListObjects("Tjeux3")
'tableau vide--------------------------------------------
      'ListBox1.List = Tb1.DataBodyRange.Value  'plante
      'ListBox1.List = [Tjeux1].Value           'plante

'tableau une seule ligne de données----------------------
      'ListBox2.List = Tb2.DataBodyRange.Value     'plante
      'ListBox2.List = [Tjeux2].Value              'plante

'tableau avec + de 2 lignes de données---------------------
      ListBox3.List = Tb3.DataBodyRange.Value     'fonctionne
      'ListBox3.List = [Tjeux3].Value               'fonctionne
   End With
   Set Tb1 = Nothing
   Set Tb2 = Nothing
   Set Tb3 = Nothing
End Sub
Merci par avance.
 

Pièces jointes

  • Listbox_Listobject.xlsm
    20.4 KB · Affichages: 9
Solution
Bonsoir
bonsoir j'arrive après la bataille mais bon
VB:
Option Explicit

Private Sub UserForm_Initialize()
Dim r As Range, i&, lstBx As MSForms.ListBox
    For i = 1 To 3
        Set r = Range("Tjeux" & i)
        Set lstBx = Me.Controls("ListBox" & i)
        lstBx.Clear: If r.Rows.Count > 1 Then lstBx.List = r.Value Else lstBx.Column = r.Resize(, 2).Value
    Next
End Sub
j'explique ou pas le pourquoi du comment et l'astuce??

cathodique

XLDnaute Barbatruc
En remerciant celles et ceux qui auront consulter le fil. J'ai trouvé une solution.
VB:
Option Explicit

Private Sub UserForm_Initialize()
   Dim Tb1 As ListObject, Tb2 As ListObject, Tb3 As ListObject

   With Sheets("feuil1")
      Set Tb1 = .ListObjects("Tjeux1")
      Set Tb2 = .ListObjects("Tjeux2")
      Set Tb3 = .ListObjects("Tjeux3")
      'tableau vide--------------------------------------------
      If Tb1.DataBodyRange Is Nothing Then
         ListBox1.Clear
      ElseIf Tb1.ListRows.Count = 1 Then
         ListBox1.AddItem Tb1.DataBodyRange(1)
      Else
         ListBox1.List = Tb1.DataBodyRange.Value
      End If

      'tableau une seule ligne de données----------------------
      If Tb2.DataBodyRange Is Nothing Then
         ListBox2.Clear
      ElseIf Tb2.ListRows.Count = 1 Then
         ListBox2.AddItem Tb2.DataBodyRange(1)
      Else
         ListBox2.List = Tb2.DataBodyRange.Value
      End If

      'tableau avec + de 2 lignes de données---------------------
      If Tb3.DataBodyRange Is Nothing Then
         ListBox3.Clear
      ElseIf Tb3.ListRows.Count = 1 Then
         ListBox3.AddItem Tb3.DataBodyRange(1)
      Else
         ListBox3.List = Tb3.DataBodyRange.Value
      End If
      ListBox3.List = Tb3.DataBodyRange.Value     'fonctionne
   End With

   Set Tb1 = Nothing
   Set Tb2 = Nothing
   Set Tb3 = Nothing
End Sub
 

Lolote83

XLDnaute Barbatruc
Bonjour,

Peut être comme ceci en utilisant non plus la propriété .List mais .RowSource

VB:
Private Sub UserForm_Initialize()
   Dim Tb1 As ListObject, Tb2 As ListObject, Tb3 As ListObject
   With Sheets("feuil1")
        Set Tb1 = .ListObjects("Tjeux1")
        Set Tb2 = .ListObjects("Tjeux2")
        Set Tb3 = .ListObjects("Tjeux3")
        
        xNbrTb1 = .Range("Tjeux1").Count: xAdrTb1 = .Range("Tjeux1").Address
        xNbrTb2 = .Range("Tjeux2").Count: xAdrTb2 = .Range("Tjeux2").Address
        xNbrTb3 = .Range("Tjeux3").Count: xAdrTb3 = .Range("Tjeux3").Address
    
'tableau vide--------------------------------------------
        'ListBox1.List = Tb1.DataBodyRange.Value  'plante
        'ListBox1.List = [Tjeux1].Value           'plante
        If xNbrTb1 < 2 Then
            ListBox1.RowSource = xAdrTb1
        Else
            ListBox1.List = [Tjeux1].Value
        End If
'tableau une seule ligne de données----------------------
        'ListBox2.List = Tb2.DataBodyRange.Value     'plante
        'ListBox2.List = [Tjeux2].Value              'plante
        If xNbrTb2 < 2 Then
            ListBox2.RowSource = xAdrTb2
        Else
            ListBox2.List = [Tjeux2].Value
        End If
'tableau avec + de 2 lignes de données---------------------
        'ListBox3.List = Tb3.DataBodyRange.Value     'fonctionne
        'ListBox3.List = [Tjeux3].Value               'fonctionne
        If xNbrTb3 < 2 Then
            ListBox3.RowSource = xAdrTb3
        Else
            ListBox3.List = [Tjeux3].Value
        End If

    End With
    Set Tb1 = Nothing
    Set Tb2 = Nothing
    Set Tb3 = Nothing
End Sub

Du coup cela devrait le faire
@+ Lolote83
 

cathodique

XLDnaute Barbatruc
Bonjour
Effectivement, c'est pas tres clair!🤔
Tu peux contourner comme ceci
For Each i In Tb2.DataBodyRange.Rows
me.ListBox2.AddItem i
'ListBox2.List = [Tjeux2].Value 'plante
Next
Bonjour,

@sousou : Dans un userform, j'ai des listboxs et combobox alimentées à partir de tableaux structurés qui devraient être au préalable remplis via d'autres userforms. Il s'avère que certains sont vides ou n'ont qu'une seule ligne de valeurs. J'utilise par exemple Listbox1.list=[Tjeux1].value mais a plante lorsque le tableau Tjeux1 est vide ou n'a qu'une seule ligne de valeur.
J'espère que c'est plus clair. Pour info, j'ai essayé Listbox1.Column=[Tjeux1].value plante aussi.
Ne fonctionne que pour 2 lignes et plus.
 

cathodique

XLDnaute Barbatruc
Bonjour,

Peut être comme ceci en utilisant non plus la propriété .List mais .RowSource

VB:
Private Sub UserForm_Initialize()
   Dim Tb1 As ListObject, Tb2 As ListObject, Tb3 As ListObject
   With Sheets("feuil1")
        Set Tb1 = .ListObjects("Tjeux1")
        Set Tb2 = .ListObjects("Tjeux2")
        Set Tb3 = .ListObjects("Tjeux3")
       
        xNbrTb1 = .Range("Tjeux1").Count: xAdrTb1 = .Range("Tjeux1").Address
        xNbrTb2 = .Range("Tjeux2").Count: xAdrTb2 = .Range("Tjeux2").Address
        xNbrTb3 = .Range("Tjeux3").Count: xAdrTb3 = .Range("Tjeux3").Address
   
'tableau vide--------------------------------------------
        'ListBox1.List = Tb1.DataBodyRange.Value  'plante
        'ListBox1.List = [Tjeux1].Value           'plante
        If xNbrTb1 < 2 Then
            ListBox1.RowSource = xAdrTb1
        Else
            ListBox1.List = [Tjeux1].Value
        End If
'tableau une seule ligne de données----------------------
        'ListBox2.List = Tb2.DataBodyRange.Value     'plante
        'ListBox2.List = [Tjeux2].Value              'plante
        If xNbrTb2 < 2 Then
            ListBox2.RowSource = xAdrTb2
        Else
            ListBox2.List = [Tjeux2].Value
        End If
'tableau avec + de 2 lignes de données---------------------
        'ListBox3.List = Tb3.DataBodyRange.Value     'fonctionne
        'ListBox3.List = [Tjeux3].Value               'fonctionne
        If xNbrTb3 < 2 Then
            ListBox3.RowSource = xAdrTb3
        Else
            ListBox3.List = [Tjeux3].Value
        End If

    End With
    Set Tb1 = Nothing
    Set Tb2 = Nothing
    Set Tb3 = Nothing
End Sub

Du coup cela devrait le faire
@+ Lolote83
Bonjour,

@Lolote83 ;): je te confirme que ton code fonctionne aussi. Juste déclarer les variables que tu as ajouté.
Merci beaucoup. Je pointe ta proposition comme solution.
 

cathodique

XLDnaute Barbatruc
Re
J'avais bien compris ton problème, c'est pourquoi je te propose cette solution
@sousou :cool:: C'est parfait. peu de ligne et efficace.
J'essaie d'apprendre à coder en utilisant les ListObjects. Tu n'as pas déclaré 'i', le code ne demande même de le déclarer malgré la présence de Option Explicit.
VB:
For Each i In Tb2.DataBodyRange.Rows
  Me.ListBox2.AddItem i
Next
Merci de m'éclairer.
 

cathodique

XLDnaute Barbatruc
Je reviens vers toi. Sur mon fichier de travail le code plante. Aurais-tu une idée?
1710514316144.png

Avec ce message d'erreur
1710514362683.png

à noter l'option explicit demande la déclaration de la variable i

Avec mes remerciements.
 

sousou

XLDnaute Barbatruc
bien sur pour la déclaration,
Pour le plantage, j'ai remarqué une chose,que je ne m'explique pas trop.
J'avais la même chose sur ton fichier.
excel ne détecte pas sur le tableau vide (tb1) les databodyrange, d’où une erreur
comme si le tableau n'avais pas été initialisé, à sa création.
Dans ton tableau vide tb1 , j'ai mis une valeur, puis je l'ai retirée, et c'est pour cela qu'il fonctionne.
Tu peu gérer ceci en utilisant le traitement d'erreur,
 
Dernière édition:

patricktoulon

XLDnaute Barbatruc
Bonsoir
bonsoir j'arrive après la bataille mais bon
VB:
Option Explicit

Private Sub UserForm_Initialize()
Dim r As Range, i&, lstBx As MSForms.ListBox
    For i = 1 To 3
        Set r = Range("Tjeux" & i)
        Set lstBx = Me.Controls("ListBox" & i)
        lstBx.Clear: If r.Rows.Count > 1 Then lstBx.List = r.Value Else lstBx.Column = r.Resize(, 2).Value
    Next
End Sub
j'explique ou pas le pourquoi du comment et l'astuce??
 

cathodique

XLDnaute Barbatruc
bien sur pour la déclaration,
Pour le plantage, j'ai remarqué une chose,que je ne m'explique pas trop.
J'avais la même chose sur ton fichier.
excel ne détecte pas sur le tableau vide (tb1) les databodyrange, d’où une erreur
comme si le tableau n'avais pas été initialisé, à sa création.
Dans ton tableau vide tb1 , j'ai mis une valeur, puis je l'ai retirée, et c'est pour cela qu'il fonctionne.
Tu peu gérer ceci en utilisant le traitement d'erreur,
Bonsoir,

Désolé pour le retard. Je remercie pour tes explications.

Bonne soirée et bon week-end
 

cathodique

XLDnaute Barbatruc
Bonsoir
bonsoir j'arrive après la bataille mais bon
VB:
Option Explicit

Private Sub UserForm_Initialize()
Dim r As Range, i&, lstBx As MSForms.ListBox
    For i = 1 To 3
        Set r = Range("Tjeux" & i)
        Set lstBx = Me.Controls("ListBox" & i)
        lstBx.Clear: If r.Rows.Count > 1 Then lstBx.List = r.Value Else lstBx.Column = r.Resize(, 2).Value
    Next
End Sub
j'explique ou pas le pourquoi du comment et l'astuce??
Bonsoir Patrick;),

Tu sais bien que tes explications sont toujours les bienvenues.
J'essaie de comprendre la bête "ListObject" mais j'avoue que j'ai beaucoup de lacunes.
Je testerai demain ton code. Je suis crevé.
Bonne fin de soirée et bon week-end:cool:
 

cathodique

XLDnaute Barbatruc
Bonjour,

@patricktoulon : C'est un régale. Merci beaucoup, c'est très clair.
Je t'avoue que je ne fais pas autant d'effort que toi pour aller au bout du bout.
Quoique bien souvent j'essaie d'approfondir mais butant sur des difficultés de compréhension, j'abandonne.

Si j'ai bien compris, il est plus avantageux d'utiliser le Range que le ListObject pour "atteindre" un tableau structuré.

Tu m'as parfaitement démontrer comment solutionner mon problème en pratiquement une seule ligne de code. Évitant ainsi, la suite de If. Je connaissais l'utilisation du ListBox.Column en faisant des extractions de données d'une BD. Mais sans avoir bien compris le pourquoi du comment. Tu viens de me l'expliquer clairement.

à la fin de la vidéo, tu m'as montré qu'après le resize dans la listbox du tableau vide, qu'il y avait bien 2 lignes vides. Tu as dit que l'on pouvait lui appliquer un Clear. Si ce n'est abusé, je voudrais que tu me donnes ta solution.

En tout cas un grand bravo pour ta vidéo très pédagogique. Encore merci, pour ton partage et ta patience.

Bonne journée.

edit: J'ai téléchargé ta vidéo. Elle est dans ma "tirelire".
 

Discussions similaires

Réponses
6
Affichages
485

Statistiques des forums

Discussions
315 093
Messages
2 116 139
Membres
112 669
dernier inscrit
Guigui2502