"Valeurs" Null dans Listbox.List [Résolu]

pijaku 12205 Messages postés jeudi 15 mai 2008Date d'inscriptionModérateurStatut 13 septembre 2017 Dernière intervention - 26 juin 2015 à 14:26 - Dernière réponse : pijaku 12205 Messages postés jeudi 15 mai 2008Date d'inscriptionModérateurStatut 13 septembre 2017 Dernière intervention
- 29 juin 2015 à 12:30
Bonjour,

Dans un exemple d'utilisation de listbox, j'ai voulu tester la propriété List des listbox, et surtout passer le contenu d'une listbox multicolonne dans une variable tableau.
Résultat non attendu : la variable tableau comporte un certain nombre de Null.

Un exemple vous parlera davantage.
Soit un userform avec :
- une combobox ComboBox1
- Une ListBox : ListBox1
- un Bouton : CommandButton1

Une feuille (Feuil1) avec trois colonnes de données (A, B, C).

Voici le code incriminé :
Option Explicit
Private F As Worksheet, TC As Variant


Private Sub UserForm_Initialize()
Dim D As Object, i As Integer

Me.ListBox1.ColumnCount = 3
Me.ListBox1.ColumnWidths = "98;98;98"
Me.ListBox1.Width = 300
Set F = Sheets("Feuil1")
TC = F.Range("A1").CurrentRegion
Set D = CreateObject("Scripting.Dictionary")
For i = 2 To UBound(TC, 1)
    D(TC(i, 1)) = ""
Next i
Me.ComboBox1.List = D.keys
End Sub

Private Sub ComboBox1_Click()
Dim i As Integer
For i = 2 To UBound(TC, 1)
   If TC(i, 1) = Me.ComboBox1.Value Then
         Me.ListBox1.AddItem TC(i, 1)
         Me.ListBox1.List(ListBox1.ListCount - 1, 1) = TC(i, 2)
         Me.ListBox1.List(ListBox1.ListCount - 1, 2) = TC(i, 3)
         'Me.ListBox1.List(ListBox1.ListCount - 1, 3) = i
    End If
Next i
End Sub

Private Sub CommandButton1_Click()
Dim Tb, i As Integer, j As Integer

Tb = ListBox1.List
For i = LBound(Tb, 1) To UBound(Tb, 1)
   For j = LBound(Tb, 2) To UBound(Tb, 2)
      Debug.Print Tb(i, j)
   Next j
Next i
End Sub


A force de chercher d'où viennent les Null, mes yeux se croisent et je ne vois plus rien!
Afficher la suite 

24 réponses

Répondre au sujet
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionModérateurStatut 11 avril 2018 Dernière intervention - Modifié par ucfoutu le 27/06/2015 à 10:44
+2
Utile
10
Mais nous n'allons tout de même pas subir sans broncher ce particularisme gênant.
- Rien à tenter en ce qui concerne la limitation à 9 de la propriété ColumnCount, dès lors qu'un "échange" doit être assuré
- En ce qui concerne par contre les colonnes résultantes indues ===>> Hé bien ===>>> forçons donc la main ===>>> ainsi (exemple) :
Private Sub CommandButton2_Click()
ListBox1.ColumnCount = 5
ListBox1.Width = 300
For i = 0 To 4
ListBox1.AddItem i
For j = 1 To ListBox1.ColumnCount
ListBox1.List(i, j) = i & " - " & j
Next
Next
Dim TB()
TB = ListBox1.List() ' on va avoir 10 colonnes ! et donc ===>>
' on "force la main pour ne laisser que les valables" ====>>
ReDim Preserve TB(ListBox1.ListCount - 1, ListBox1.ColumnCount - 1)
For i = LBound(TB, 1) To UBound(TB, 1)
For j = LBound(TB, 2) To UBound(TB, 2)
Debug.Print TB(i, j)
Next
Next
End Sub

Marche bien.

Précisions :
- j'ai également essayé avec une seule colonne et le même code (sauf, bien évidemment, l'alimentation de la listbox) ===>> marche bien
Je laisse enfin Franck, qui a ouvert cette discussion, faire et déposer un petit snippet à ce sujet (j'ai la flemme). Le titre pourrait être : ListBox vers tableau sans faille



________________________
Nul ne saurait valablement coder ce qu'il ne saurait exposer clairement.
Cette réponse vous a-t-elle aidé ?  
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionModérateurStatut 11 avril 2018 Dernière intervention > pijaku 12205 Messages postés jeudi 15 mai 2008Date d'inscriptionModérateurStatut 13 septembre 2017 Dernière intervention - 29 juin 2015 à 11:02
Tout-à-fait !
Mais cela supposerait alors que tu connaisses à l'avance les dimensions de la listbox et qu'elles soient réellement fixes (constantes) !
pijaku 12205 Messages postés jeudi 15 mai 2008Date d'inscriptionModérateurStatut 13 septembre 2017 Dernière intervention > ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionModérateurStatut 11 avril 2018 Dernière intervention - 29 juin 2015 à 11:05
Mais cela supposerait alors que tu connaisses à l'avance les dimensions de la listbox et qu'elles soient réellement fixes (constantes) !
Oui, bien sur. J'ai bien conscience que ce type de cas doit être extrèmement rare d'ailleurs. Mais c'est juste pour tester aujourd'hui.
Ce qui m'a intrigué c'est l'erreur "proposée" par Microsoft qui semble ne pas coller avec la réalité :
erreur de compilation "impossible d'affecter à une variable tableau" en surlignant la ligne
Tb = ListBox1.List()

Or, depuis le début de cette discussion, nous affectons bien la propriété List à une variable tableau sans aucun souci de compilation!
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionModérateurStatut 11 avril 2018 Dernière intervention > pijaku 12205 Messages postés jeudi 15 mai 2008Date d'inscriptionModérateurStatut 13 septembre 2017 Dernière intervention - 29 juin 2015 à 11:13
Ah oui .. Je vois ce que tu veux dire.
La raison est simple :
- on ne peut redimensionner (sans preserve) un tableau qui a été dimensionné
- or (comme dit plus haut), l'affectation par Tb = ListBox1.List() inclut un dimensionnement à 10 systématique.
Il en va différemment si le tableau n'est pas encore dimensionné ( dim TB() )
pijaku 12205 Messages postés jeudi 15 mai 2008Date d'inscriptionModérateurStatut 13 septembre 2017 Dernière intervention > ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionModérateurStatut 11 avril 2018 Dernière intervention - 29 juin 2015 à 11:15
Ok.
Oui, je comprends mieux maintenant.
Merci.
pijaku 12205 Messages postés jeudi 15 mai 2008Date d'inscriptionModérateurStatut 13 septembre 2017 Dernière intervention - 29 juin 2015 à 12:30
Le snippet est en ligne.
Merci Jacques et cs_MPi.
Amicalement
Franck
Commenter la réponse de ucfoutu
cs_MPi 3863 Messages postés mardi 19 mars 2002Date d'inscription 13 mars 2018 Dernière intervention - 26 juin 2015 à 15:02
0
Utile
1
Bonjour,

Quand le contrôle a plusieurs colonne, il faut faire un AddItem seul avant de remplir les lignes
For i = 2 To UBound(TC, 1)
If TC(i, 1) = Me.ComboBox1.Value Then
Me.ListBox1.AddItem 'tout seul
Me.ListBox1.List(ListBox1.ListCount - 1, 0) = TC(i, 1)
Me.ListBox1.List(ListBox1.ListCount - 1, 1) = TC(i, 2)
Me.ListBox1.List(ListBox1.ListCount - 1, 2) = TC(i, 3)
'Me.ListBox1.List(ListBox1.ListCount - 1, 3) = i
End If
Next i

pijaku 12205 Messages postés jeudi 15 mai 2008Date d'inscriptionModérateurStatut 13 septembre 2017 Dernière intervention - 26 juin 2015 à 15:18
Bonjour cs_MPi,

Cela ne change rien au schmilblick.
Je me retrouve bien avec des valeurs Null dans ma ListBox.
Regarde ce classeur :
http://www.cjoint.com/c/EFAnrWjCxmV
Tu clic sur le bouton, fais un choix dans la combobox et clic sur le bouton.
Commenter la réponse de cs_MPi
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionModérateurStatut 11 avril 2018 Dernière intervention - Modifié par ucfoutu le 26/06/2015 à 15:17
0
Utile
1
Bonjour, Franck,
Je ne comprends personnellement pas l'utilité de passer par un dico.
Regarde ce que fait ceci (avec la listbox sur une feuille de calcul nommée "Donnees") :
Dim toto As Range
Set toto = Worksheets("Donnees").Range("A1").CurrentRegion
ListBox1.ColumnCount = toto.Columns.Count
ListBox1.ListFillRange = "Donnees!" & toto.Address


et si la loistboàx est sur un userform,, changer ListFillRange par Rowsource ===>>

 Dim toto As Range
Set toto = Worksheets("Donnees").Range("A1").CurrentRegion
ListBox1.ColumnCount = toto.Columns.Count
ListBox1.RowSource = "Donnees!" & toto.Address

________________________
Nul ne saurait valablement coder ce qu'il ne saurait exposer clairement.
pijaku 12205 Messages postés jeudi 15 mai 2008Date d'inscriptionModérateurStatut 13 septembre 2017 Dernière intervention - 26 juin 2015 à 15:24
Bonjour Jacques,

Peu importe, il ne s'agit que d'un exemple.

1- Je remplit une combobox1 avec les valeurs de la colonne A sans doublon (l'intérêt du dictionary n'est pas avérée dans ce cas, je te l'accorde, mais il ne change pas le problème).
2- L'événement Combobox_Click remplit ma listbox des données correspondantes au choix fait dans la combobox.
Je te remets cette Sub corrigée par cs_MPi :
Private Sub ComboBox1_Click()
Dim i As Integer
For i = 2 To UBound(TC, 1)
   If TC(i, 1) = Me.ComboBox1.Value Then
         Me.ListBox1.AddItem  'tout seul
         Me.ListBox1.List(ListBox1.ListCount - 1, 0) = TC(i, 1)
         Me.ListBox1.List(ListBox1.ListCount - 1, 1) = TC(i, 2)
         Me.ListBox1.List(ListBox1.ListCount - 1, 2) = TC(i, 3)
    End If
Next i
End Sub

3- Je restitue dans la feuille
Private Sub CommandButton1_Click()
Dim Tb, i As Integer, j As Integer

Tb = ListBox1.List
Range("A12").Resize(UBound(Tb, 1), UBound(Tb, 2)) = Tb
Me.Hide
'For i = LBound(Tb, 1) To UBound(Tb, 1)
'   For j = LBound(Tb, 2) To UBound(Tb, 2)
'      Debug.Print Tb(i, j)
'   Next j
'Next i

End Sub

Pourquoi, lors de la restitution, je me retrouve avec un tableau Tb(1 To x, 1 To 9), alors que ma ListBox contient x lignes sur 3 colonnes (et pas 9)?

Qu'est ce qui, dans le code ou les propriétés des contrôles me perturbe le bouzin à ce point?
Commenter la réponse de ucfoutu
pijaku 12205 Messages postés jeudi 15 mai 2008Date d'inscriptionModérateurStatut 13 septembre 2017 Dernière intervention - 26 juin 2015 à 16:21
0
Utile
Un second exemple qui vous permet de ne pas avoir à remplir une feuille de données.
Donc : sans feuille
1 userform, avec 1 ComboBox (ComboBox1) et 1 ListBox (ListBox1)
Le code :
Option Explicit

Private TC

Private Sub UserForm_Initialize()
Dim Lig As Long
Me.ListBox1.ColumnCount = 3
Me.ListBox1.ColumnWidths = "98;98;98"
Me.ListBox1.Width = 300

Rempli_TC

MsgBox "=> 1ère dim : " & UBound(TC, 1) & vbCrLf & "=> 2ème dim : " & UBound(TC, 2)
For Lig = 1 To 4
   ComboBox1 = TC(Lig, 1)
   If ComboBox1.ListIndex = -1 Then ComboBox1.AddItem TC(Lig, 1)
Next Lig
End Sub

Private Sub ComboBox1_Click()
Dim i As Integer, Tb
For i = 2 To UBound(TC, 1)
   If TC(i, 1) = Me.ComboBox1.Value Then
         Me.ListBox1.AddItem  'tout seul
         Me.ListBox1.List(ListBox1.ListCount - 1, 0) = TC(i, 1)
         Me.ListBox1.List(ListBox1.ListCount - 1, 1) = TC(i, 2)
         Me.ListBox1.List(ListBox1.ListCount - 1, 2) = TC(i, 3)
   End If
Next i
Tb = ListBox1.List
For i = LBound(Tb, 1) To UBound(Tb, 1)
   For j = LBound(Tb, 2) To UBound(Tb, 2)
      Debug.Print Tb(i, j)
   Next
Next
End Sub

Sub Rempli_TC()
ReDim TC(1 To 4, 1 To 3)
TC(1, 1) = "Jerome"
TC(2, 1) = "Mickael"
TC(3, 1) = "Jerome"
TC(4, 1) = "Valerie"
TC(1, 2) = "pruneau"
TC(2, 2) = "peche"
TC(3, 2) = "poire"
TC(4, 2) = "spaghetti"
TC(1, 3) = 1
TC(2, 3) = 10
TC(3, 3) = 3
TC(4, 3) = 5
End Sub


J'obtiens, en choisissant Jerome dans la combobox, dans la fenêtre d'édition :
Jerome
poire
3
Null
Null
Null
Null
Null
Null
Null
Jerome
poire
3
Null
Null
Null
Null
Null
Null
Null
Jerome
poire
3
Null
Null
Null
Null
Null
Null
Null
Commenter la réponse de pijaku
cs_MPi 3863 Messages postés mardi 19 mars 2002Date d'inscription 13 mars 2018 Dernière intervention - 26 juin 2015 à 17:58
0
Utile
C'est effectivement intriguant...
Dès qu'on arrive à
Me.ListBox1.AddItem

Le listbox contient 9 items (le max possible) à NULL et on en remplit que 3. Il en reste donc 6 NULL

C'est bien la première fois que je remarque quelque chose comme ça... (?!)
Commenter la réponse de cs_MPi
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionModérateurStatut 11 avril 2018 Dernière intervention - Modifié par ucfoutu le 26/06/2015 à 18:14
0
Utile
2
Heu ...
Ton exemple (le dernier) ne m'affiche aucun null, ni colonnes "indues".
Il tourne sans ces problèmes. Es-tu certain d'avoir mis ici un copié/collé de ton essai ? (ce n'est pas dit, car, par exemple, il m'a fallu déclarer la variable j pour correspondre à l'option Exlicit ...

Il se peut également que cet essai soit fait sur un userform d'un projet comportant d'autres objets et que des nommages de variables soient en conflit entre un module et l'autre. Il est même presque certain que telle soit la raison de tes mésaventures.

Refait cet essai sur un classeur tout neuf et tu verras ===>>> aucun problème !

EDIT : Ah pardon ! Tu parlais de l'affichage dans le Debug.print !
Eh oui, mais le debug.print affiche tout, y compris les caractères null de terminaison ( chr(0) ).

________________________
Nul ne saurait valablement coder ce qu'il ne saurait exposer clairement.
cs_MPi 3863 Messages postés mardi 19 mars 2002Date d'inscription 13 mars 2018 Dernière intervention - 26 juin 2015 à 20:17
J'ai utilisé son code sur un nouveau projet avec seulement un userform.
En pas à pas, en arrivant sur Listbox1.Additem, si on regarde dans la fenêtre Espion, on y voit 10 items créés par défaut... étrange...
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionModérateurStatut 11 avril 2018 Dernière intervention > cs_MPi 3863 Messages postés mardi 19 mars 2002Date d'inscription 13 mars 2018 Dernière intervention - 26 juin 2015 à 20:49
Bonjour, MPI,
Pas vraiment étrange ! Debug.Print ne "gère" pas totalement et prend également en compte tout ce qui permet l'affichage en colonnes.
Commenter la réponse de ucfoutu
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionModérateurStatut 11 avril 2018 Dernière intervention - 26 juin 2015 à 21:36
0
Utile
J'ai dit des co*****ries !
Après un bon repas et un bon vin ===>> je m'y suis attelé avec plusieurs tests.
Ce n'est pas Debug.print, qui est le responsable, mais :
Tb = ListBox1.List

qui déc***e au moins autant que moi avant repas et vin ...
Preuve :
Private Sub UserForm_Initialize()
Dim Lig As Long
ListBox1.ColumnCount = 3
ListBox1.ColumnWidths = "98;98;98"
ListBox1.Width = 300
For i = 0 To 4
ListBox1.AddItem i
For j = 1 To 3
ListBox1.List(i, j) = j
Next
Next
Dim TB()
ReDim TB(1 To ListBox1.ListCount, 1 To ListBox1.ColumnCount)
' GoTo 10
TB = ListBox1.List()
For i = LBound(TB, 1) To UBound(TB, 1)
For j = LBound(TB, 2) To UBound(TB, 2)
'MsgBox TB(i, j)
Debug.Print TB(i, j)
Next
Next
Exit Sub
10:
For i = 0 To ListBox1.ListCount - 1
For j = 0 To ListBox1.ColumnCount - 1
TB(i + 1, j + 1) = ListBox1.List(i, j)
Next
Next
For i = LBound(TB, 1) To UBound(TB, 1)
For j = LBound(TB, 2) To UBound(TB, 2)
'MsgBox TB(i, j)
Debug.Print TB(i, j)
Next
Next
End Sub

Si on commente GOTO 10 (on passe par la ligne en cause) ===>>> problème
Si on décommente GOTO 10 (on "dresse" le tableau à la "classique") ===>>> pas de problème.
Conclusion : l'alimentation d'une matrice toto à partir de la liste d'une listbox par la méthode toto = nom_listebox() est bancale et on ne peut lui faire confiance.
Commenter la réponse de ucfoutu
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionModérateurStatut 11 avril 2018 Dernière intervention - 26 juin 2015 à 23:41
0
Utile
Le problème de
TB = ListBox1.List()


ne se pose qu'avec un tableau à plusieurs dimensions.
Il ne se pose pas si une seule dimension.
Preuve ===>>>
Private Sub CommandButton1_Click()
Dim Lig As Long
For i = 0 To 4
ListBox1.AddItem i
Next
Dim TB()
ReDim TB(1 To ListBox1.ListCount)
TB = ListBox1.List()
For i = LBound(TB, 1) To UBound(TB, 1)
Debug.Print TB(i, j)
Next
Exit Sub
End Sub

Commenter la réponse de ucfoutu
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionModérateurStatut 11 avril 2018 Dernière intervention - Modifié par ucfoutu le 27/06/2015 à 08:01
0
Utile
Ah !!!!
Lu dans l'aide VBA :
1)
La définition de la propriété ColumnCount sur 0 affiche zéro colonne et la définition sur -1 affiche toutes les colonnes disponibles. Pour une source de données indépendante, il y a une limite de 10 colonnes (0 à 9).

2)
Source de données
Emplacement des données auquel est lié un contrôle, par exemple une cellule d'une feuille de calcul. La valeur en cours d'une source de données peut être enregistrée dans la propriété Value d'un contrôle. Toutefois, le contrôle n'enregistre pas les données, il n'affiche que les informations enregistrées dans la source de données.


- L'échange entre TB et ListBox1.List() est donc limité à 10 colonnes, de 0 à 9 dédiées à TB.
De fait, quel que soit le nombre de colonnes (de 0 à 9), TB aura toujours 10 colonnes (systématiquement). Les colonnes "superflues" contiennent des NULL
- Si cette hypothèse est vraie, on ne devrait plus avoir de NULL avec une listbox dont la propriété ColumnCount = 9 ===>>> voyons donc ===>>
Private Sub UserForm_Initialize()
Dim Lig As Long
ListBox1.ColumnCount = 9
ListBox1.ColumnWidths = "98;98;98"
ListBox1.Width = 300
For i = 0 To 2
ListBox1.AddItem i
For j = 1 To 9
ListBox1.List(i, j) = j
Next
Next
Dim TB()
TB = ListBox1.List()
For i = LBound(TB, 1) To UBound(TB, 1)
For j = LBound(TB, 2) To UBound(TB, 2)
Debug.Print TB(i, j)
Next
Next
End Sub

===>>> c'est ma foi bien vrai.

Et donc : (tiens ... j'ai pourtant pris en horreur cette expression depuis que j'entends tous les jours et à tout bout de champ des "et donc euuuuhhhhh ...", des "en fait euuuhhh. ..." aussi laids que disonnants et souvent abusifs, voire indus)
1) nombre de NULL toujours égal à : 9 - ListBox1.ColumnCount
2) impossible de mettre en oeuvre un tel "échange" avec un columncount > 9

________________________
Nul ne saurait valablement coder ce qu'il ne saurait exposer clairement.
Commenter la réponse de ucfoutu
pijaku 12205 Messages postés jeudi 15 mai 2008Date d'inscriptionModérateurStatut 13 septembre 2017 Dernière intervention - 29 juin 2015 à 08:32
0
Utile
Bonjour,

Je vous laisse un week end pour m'occuper de Théo et... Boum Bardafff tout est résolu le lundi matin!
Merci.
Je vais relire tout cela, faire tous les tests que vous avez effectués et revenir après avoir assimilé le tout.

Et donc euuuuhhhhh ...en fait euuuhhh, je reviendrais avec le premier jet du texte d'un snippet à ce sujet.
Commenter la réponse de pijaku

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.