re,
y a t il une colonne "Prénom" avec "é" , "P",... ?
TbLigne vaut quoi ? --> sur la ligne jaune , met le curseur sur TbLigne , il doit apparaître la valeur
le nom de la textbox est bien "PrenomTextBox" --> voir accent, majuscule,...
@+JP
Version imprimable
re,
y a t il une colonne "Prénom" avec "é" , "P",... ?
TbLigne vaut quoi ? --> sur la ligne jaune , met le curseur sur TbLigne , il doit apparaître la valeur
le nom de la textbox est bien "PrenomTextBox" --> voir accent, majuscule,...
@+JP
re,
TbCols("Prénom").DataBodyRange(TbLigne).Value
TbCols("Prénom") --> colonne "Prénom"
.DataBodyRange(TbLigne) --> la ligne dans la colonne
.Value --> la valeur de la cellule ( ligne , colonne)
@+JP
re,
juste avant TbCols("Prénom").DataBodyRange(TbLigne).Value
ecrit msgbox TbLigne
et relance
@+JP
Salut.
Perso, avec les tableaux, j'utilise beaucoup les plages nommées.
Sur base du tableau suivant, on peut utiliser un code de remplissage qui n'utilise pratiquement pas le listobject (juste pour tester s'il est vide ou pas)
Pièce jointe 308946
Voici un code qui remplit le tableau en testant qu'il est vide ou pas.
Sur un tableau vide, tu peux tester et entrer les deux contacts suivants:Code:
1
2
3
4
5
6
7
8
9
10
11 Sub AddContact(FirstName As String, LastName As String) Dim RowIndex As Long If Range("t_contacts").ListObject.DataBodyRange Is Nothing Then RowIndex = 1 Else RowIndex = Range("t_Contacts").Rows.Count + 1 End If Range("t_contacts[prénom]")(RowIndex).Value = FirstName Range("t_contacts[nom]")(RowIndex).Value = LastName End Sub
Personnellement, je trouve que c'est plus simple que de travailler avec les listobject.Code:
1
2
3
4 Sub Test() AddContact "Pierre", "Durand" AddContact "Martine", "Dupont" End Sub
De plus, j'essaie de ne jamais effectuer les traitements directement dans les userform. Je préfère découpler et utiliser le userform pour ce qu'il est, à savoir un auxiliaire de saisie. Lorsque les données sont saisies, on les passe en paramètres à une fonction hors userform qui réalise le process. On utilise cette méthode tant pour l'ajout que pour la suppression. Ca permet de tester chaque fonctionnalité en dehors d'un contexte où elle utilise peut-être des mauvaises valeurs de variables (cas typique d'une ligne supprimée qui décale un objet Range). Tu supprimes une ligne en lui passant son numéro, et tu ajoutes sur une ligne en lui passant des données via une autre fonction. Les fonctions utilisant chacune leurs propres variables, aucun risque de se mélanger les pinceaux... (C'est ma façon psychorigide de coder ;) )
si je relance sans point d'arrêt je plante Excel
avec arrêt sur ligne msgbox :
Pièce jointe 308949
Voici le code qui me posait souci (Tableau et Plage nommée)
Cdt, EricCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 Private Sub AddIntervenantBtn_Click() If UserForm1.NomTextBox.Value <> "" Then Range("A2").Select Selection.ListObject.ListRows.Add (1) ActiveCell.Value = UserForm1.NomTextBox ActiveCell.Offset(0, 1).Value = UserForm1.PrenomTextBox Unload Me UserForm1.Show Else Unload Me UserForm1.Show End If End Sub Private Sub SupprIntervenantBtn_Click() With ComboBox1 li = .ListIndex + 2 Rows(li & ":" & li).Select Selection.Delete Shift:=xlUp Unload Me UserForm1.Show End With End Sub Private Sub ComboBox1_Change() With ComboBox1 PrenomLabel.Caption = .Column(1, .ListIndex) End With End Sub Private Sub UserForm_Initialize() ComboBox1.RowSource = "=Plage" End Sub
re,
l'erreur est donc TbLigne qui n'a pas de valeur ;)
TbLigne prend la valeur de TbRows.Count --> nombre de ligne de TbRows --> donc la dernière ligne
on pourrait tester avec msgbox TbRows.Count , mais autant contrôler si TbRows est bien déclaré 8O
Dim TbRows As ListRows --> en tête de module
et
Set TbRows = Tb.ListRows dans procédure "Initialise"
et
Call Initialise dans Private Sub UserForm_Initialize()
@+JP
Pour continuer dans les exemples de manip, tu peux créer également une fonction qui supprime. Le code suivant, issu du tableau illustré ci-dessous, supprime une ligne puis en ajoute une. Ici, les fonctions ne gèrent pas les erreurs. C'est normalement au code appelant (le clic sur un des boutons) à gérer les erreurs qui remontent des autres couches de l'appli. Par exemple, si l'ID n'existe pas, ça plante. C'est donc la fonction qui appelle DeleteContact qui doit gérer l'erreur avec une gestionnaire d'erreur adéquat. On pourrait aussi gérer l'erreur en interne et renvoyer soit 0 (tout est ok) soit un code d'erreur qui serait traité par la suite dans la fonction appelante.
Mais à nouveau, en procédant de la sorte, tu crées des fonctions qui ne font qu'une seule chose, et tu peux tester et retester ces fonctions dans tous les sens... Ca donne l'impression d'être plus complexe, mais c'est au final beaucoup plus simple à écrire, à tester et à maintenir.
Pièce jointe 308954
Code:
1
2
3
4
5
6
7
8
9
10
11 Sub DeleteContact(ID As String) Dim RowIndex As Long RowIndex = Application.Match(ID, Range("t_contacts[ID]"), 0) Range("t_contacts").ListObject.ListRows(RowIndex).Delete End Sub Sub Test() DeleteContact "X485" AddContact "Alain", "Térieur", "Z111" End Sub
bonjour Pierre,
j'aime bien ton code , qui est "tout simple" :D (traduire par "clair' ;) )
dans mon exemple qui est plus "lourd" , j'ai voulu démontrer le croisement des colonne et ligne avec des "nommé"
@+JP
Bonjour Pierre
J'aurais eu grand besoin de tes lumières plus haut 01/09 14h40 pour me dire ce qui cloche dans ce code (plage nommée) :calim2:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 Private Sub AddIntervenantBtn_Click() If UserForm1.NomTextBox.Value <> "" Then Range("A2").Select Selection.ListObject.ListRows.Add (1) ActiveCell.Value = UserForm1.NomTextBox ActiveCell.Offset(0, 1).Value = UserForm1.PrenomTextBox Unload Me UserForm1.Show Else Unload Me UserForm1.Show End If End Sub Private Sub SupprIntervenantBtn_Click() With ComboBox1 li = .ListIndex + 2 Rows(li & ":" & li).Select Selection.Delete Shift:=xlUp Unload Me UserForm1.Show End With End Sub Private Sub ComboBox1_Change() With ComboBox1 PrenomLabel.Caption = .Column(1, .ListIndex) End With End Sub Private Sub UserForm_Initialize() ComboBox1.RowSource = "=Plage" End Sub
re,
moi çà fonctionne , mais j'ai que un onglet :P
sheets(monsheet).select
UserForm1.show
@+JP
Mais c'est déjà le cas JP et ça plante toujours
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 Dim Tb As ListObject Dim TbRows As ListRows Dim TbCols As ListColumns Private Sub UserForm_Initialize() Call Initialise End Sub Private Sub ComboBox1_Change() With ComboBox1 Me.PrenomLabel.Caption = .Column(1, .ListIndex) End With End Sub Private Sub AddIntervenantBtn_Click() If UserForm1.NomTextBox.Value <> "" Then 'ajouter ligne Tb.ListRows.Add 'derniere ligne TbLigne = TbRows.Count 'ecrire nom TbCols("Nom").DataBodyRange(TbLigne).Value = UserForm1.NomTextBox.Value 'ecrire prenom MsgBox TbLigne TbCols("Prénom").DataBodyRange(TbLigne).Value = UserForm1.PrenomTextBox.Value 'initialise ComboBox1 ComboBox1.RowSource = Range("Intervenants[#data]").Address End If End Sub Private Sub SupprIntervenantBtn_Click() 'ligne à supprimer TbLigne = UserForm1.ComboBox1.ListIndex + 1 'supprime ligne Tb.ListRows(TbLigne).Delete 'initialise ComboBox1 ComboBox1.RowSource = Range("Intervenants[#data]").Address End Sub Private Sub Initialise() Set Tb = ActiveSheet.ListObjects("Intervenants") Set TbRows = Tb.ListRows ' contient les lignes Set TbCols = Tb.ListColumns ' contient les colonnes 'ComboBox1.RowSource = Range("Intervenants[[#data],[Nom]]").Address ComboBox1.RowSource = Range("Intervenants[#data]").Address End Sub
re,
dans cette ligne,
Set Tb = ActiveSheet.ListObjects("Intervenants")
AvtiveSheet est celui qui contient le tableau
mais à l'ouverture de ton fichier , quel est l'onglet actif ?
avant d'appeler le form , selectionner le bon onglet OU revoir le code
en indiquant Sheets("NomduSheet").ListObjects("Intervenants")
et revoir tous les activesheet
@+JP
Pour être sûr de travailler sur le bon tableau, quelle que soit la feuille active, tu peux utiliser
set tbl = range("Intervenants").ListObject sans te tracasser de la feuille sur laquelle il se trouve ou que ce soit la bonne feuille qui soit activée.
re,
cool !!..:P
direct je modifie..
@+JP
J'illustrais cette possibilité dans les codes que j'ai donnés, pour l'ajout ou pour le delete
If Range("t_contacts").ListObject.DataBodyRange Is Nothing Then pour voir si le tableau est vide
Range("t_contacts").ListObject.ListRows(RowIndex).Delete pour supprimer la ligne du tableau (en se limitant donc aux colonnes dudit tableau)
;)
Excuse-moi JP, j'étais OFF
Pour ce cas je suis sur un seul onglet pour rester simple, j'ai assez de :aie: comme ça
Donc de toute façon à l'ouverture c'est bien Feuil1 qui est active
Pour Pierre (pour lui montrer que j'ai un peu creusé la plage nommée sur ses recommandations) :mrgreen:
Oui si la plage n'est pas nommée pour la Feuille dont elle est issue, alors elle s'applique à tout le classeur actif
Eric
En fait, le nom d'un tableau est unique dans le classeur. Dès lors, le nom utilisé est unique aussi, et donc la plage nommée avec un nom de tableau s'applique à la zone de données du tableau et s'applique donc à tout le classeur actif.
De sorte que si tu as un tableau nommé t_Contacts, tu peux utiliser la plage nommée t_Contacts partout dans ton code, elle fera toujours référence à la zone de données dudit tableau.
Entre autres avantages, utiliser Range("t_Contacts") pour pointer vers la zone de données du tableau, et notamment utiliser range("...").ListObject pour récupérer le listobject, permet que ton code ne doit pas être modifié si tu déplaces ton tableau sur une autre feuille ou si tu renommes ta feuille. Tu n'as en fait même pas besoin de savoir sur quelle feuille ton tableau se trouve ni comment elle se nomme, et ton code passe au travers de tous les déplacements, sur la feuille même, et vers une autre feuille également.