Code VBA sur formulaire incorrect
Bonjour,
Je suis nouvelle sur ce forum...pardonnez moi si je ne poste pas au bon endroit...
Je suis en train de créer une petite base de données pour mon entreprise, et mon responsable souhaite que je mette en place un formulaire, plus "visuel" qu'un gros tableau Excel.
Novice en codage VBA, je me suis lancée dans la création d'un formulaire sur Visual Basic, mais malheureusement mon code ne fonctionne pas...pourriez-vous m'aider et identifier d'ou vient le problème??
Je mets en copie mon fichier Excel et ci-dessous mon code.
Merci par avance de votre aide
Option Explicit
Dim Ws As Worksheet
'Pour le formulaire
Private Sub UserForm_Initialize()
Dim J As Long
Dim I As Integer
Set Ws = Sheets("Informations personnelles") 'Correspond au nom de l'onglet dans le fichier Excel
With Me.ComboBox1
For J = 2 To Ws.Range("D" & Rows.Count).End(xlUp).Row
.AddItem Ws.Range("D" & J)
Next J
End With
For I = 0 To 13
Me.Controls("TextBox" & I).Visible = True
Next I
End Sub
'Pour la liste déroulante Nom
Private Sub ComboBox1_Change()
Dim Ligne As Long
Dim I As Integer
If Me.ComboBox1.ListIndex = -1 Then Exit Sub
Ligne = Me.ComboBox1.ListIndex + 2
ComboBox1 = Ws.Cells(Ligne, "D")
For I = 1 To 13
Me.Controls("TextBox" & I) = Ws.Cells(Ligne, I + 2)
Next I
End Sub
'Pour le bouton Nouveau salarié
Private Sub CommandButton1_Click()
Dim L As Integer
If MsgBox("Confirmez-vous l'insertion de ce nouveau salarié ?", vbYesNo, "Demande de confirmation d'ajout") = vbYes Then
L = Sheets("Informations personnelles").Range("a65536").End(xlUp).Row + 1 'Pour placer le nouvel enregistrement à la première ligne de tableau non vide
Range("D" & L).Value = ComboBox1
Range("E" & L).Value = TextBox1
Range("F" & L).Value = TextBox2
Range("J" & L).Value = TextBox3
Range("I" & L).Value = TextBox4
Range("K" & L).Value = TextBox5
Range("N" & L).Value = TextBox6
Range("O" & L).Value = TextBox7
Range("L" & L).Value = TextBox8
Range("M" & L).Value = TextBox9
Range("P" & L).Value = TextBox10
Range("Q" & L).Value = TextBox11
Range("G" & L).Value = TextBox12
Range("H" & L).Value = TextBox13
End If
End Sub
'Pour le bouton Modifier
Private Sub CommandButton2_Click()
Dim Ligne As Long
Dim I As Integer
If MsgBox("Confirmez-vous la modification de ce salarié ?", vbYesNo, "Demande de confirmation de modification") = vbYes Then
If Me.ComboBox1.ListIndex = -1 Then Exit Sub
Ligne = Me.ComboBox1.ListIndex + 2
Ws.Cells(Ligne, "D") = ComboBox1
For I = 1 To 13
If Me.Controls("TextBox" & I).Visible = True Then
Ws.Cells(Ligne, I + 2) = Me.Controls("TextBox" & I)
End If
Next I
End If
End Sub
'Pour le bouton Quitter
Private Sub CommandButton3_Click()
Unload Me
End Sub
Bonjour
voila une petite modife a toi de voir
A+
Maurice
Private Sub UserForm_Initialize()
Dim J As Long
Dim I As Integer
Set Ws = Sheets("Informations personnelles") 'Correspond au nom de l'onglet dans le fichier Excel
With Me.ComboBox1
For J = 6 To Ws.Range("D" & Rows.Count).End(xlUp).Row ' a voir
.AddItem Ws.Range("D" & J)
Next J
End With
For I = 1 To 13 ' a voir
Me.Controls("TextBox" & I).Visible = True
Next I
End Sub
'Pour la liste d?roulante Nom
Private Sub ComboBox1_Change()
Dim Ligne As Long
Dim I As Integer
If Me.ComboBox1.ListIndex = -1 Then Exit Sub
Ligne = Me.ComboBox1.ListIndex + 6 ' A voir
ComboBox1 = Ws.Cells(Ligne, "D")
For I = 1 To 13
Me.Controls("TextBox" & I) = Ws.Cells(Ligne, I + 2)
Next I
End Sub
Bonjour,
Tu essaies de rendre visible un TextBox0 qui n'existe pas !
Au demeurant, si tu n'as pas mis la propriété Visible de tes TextBox à False, il n'y a aucune raison que le Userform s'ouvre avec des Textbox masqués ! Et si tu l'as fait, ce serait vraiment du vice de les masquer pour les démasquer à l'initialisation !
Ceci pour te dire que ce type de commande n'a rien à faire dans une Initialize : tu définis les propriétés par défaut des contrôles, celles qu'ils auront à l'ouverture, à chaque fois, et tu réserves l'initialisation à ce qui ne peut être défini par défaut.
AddItem n'est pas ce qu'il y a de mieux... Utilise List pour affecter ta liste à la Combo...
Tu utilises un tableau Excel, c'est bien à condition de s'en servir
Tu peux donc définir ta liste à partir du tableau en le redimensionnant à 1 colonne, liste que tu affectes à la Combo.
Aucun besoin de la feuille que tu peux ignorer. Et tu peux éviter de la mettre en variable module (ce qui n'est pas à priori une très bonne idée...)
Bilan des suggestions :
Private Sub UserForm_Initialize()
Dim Lst
Lst = [tblInfosemployé].Resize(, 1).Value
ComboBox1.List = Lst
End Sub
Tu peux tester cela, ça fonctionne !
Petite dernière remarque : place le code que tu cites dans un post sous balise Code, il en sera plus lisible et mieux lu... Je ne cache pas que le plus souvent je ne lis pas le code lâché en vrac dans un post, ce qui est dommage pour le tien qui est quasi parfaitement indenté, tout à fait à ma convenance sur ce point).
Nb- Je n'ai pas lu le reste...
Cordialement.
Bonjour,
Tu essaies de rendre visible un TextBox0 qui n'existe pas !
Au demeurant, si tu n'as pas mis la propriété Visible de tes TextBox à False, il n'y a aucune raison que le Userform s'ouvre avec des Textbox masqués ! Et si tu l'as fait, ce serait vraiment du vice de les masquer pour les démasquer à l'initialisation !
Ceci pour te dire que ce type de commande n'a rien à faire dans une Initialize : tu définis les propriétés par défaut des contrôles, celles qu'ils auront à l'ouverture, à chaque fois, et tu réserves l'initialisation à ce qui ne peut être défini par défaut.
AddItem n'est pas ce qu'il y a de mieux... Utilise List pour affecter ta liste à la Combo...
Tu utilises un tableau Excel, c'est bien à condition de s'en servir
, un tel tableau donne lieu à insertion automatique d'un nom par Excel, ce nom correspond à la partie données (hors en-tête), et il est utilisable en VBA à l'instar d'un nom de plage. Tu peux donc définir ta liste à partir du tableau en le redimensionnant à 1 colonne, liste que tu affectes à la Combo.
Aucun besoin de la feuille que tu peux ignorer. Et tu peux éviter de la mettre en variable module (ce qui n'est pas à priori une très bonne idée...)
Bilan des suggestions :
Private Sub UserForm_Initialize() Dim Lst Lst = [tblInfosemployé].Resize(, 1).Value ComboBox1.List = Lst End Sub
Tu peux tester cela, ça fonctionne !
Petite dernière remarque : place le code que tu cites dans un post sous balise Code, il en sera plus lisible et mieux lu... Je ne cache pas que le plus souvent je ne lis pas le code lâché en vrac dans un post, ce qui est dommage pour le tien qui est quasi parfaitement indenté, tout à fait à ma convenance sur ce point).
Nb- Je n'ai pas lu le reste...
Cordialement.
Bonjour,
Merci beaucoup pour ton explication. Je ne suis pas sûre d'avoir tout saisi, mais je m'accroche
Toutefois, le code que tu me proposes ne me permet pas d'afficher les informations de la personne sélectionnée dans le formulaire...ou alors j'ai mal compris...
Bonjour
tu enlever ce code car il sert a rien
'ComboBox1 = Ws.Cells(Ligne, "D")
A+
Maurice
Re,
Je ne t'ai fournis que l'Initialize... lequel se borne à alimenter ta Combo, le reste vient après.
Un petit complément sur l'Initialize :
Private Sub UserForm_Initialize()
Dim Lst
Lst = [tblInfosemployé].Resize(, 1).Value
ComboBox1.List = Lst
MultiPage1.Value = 0
End Sub
La dernière ligne est utile pour s'assurer que le Userform s'ouvre sur la première page, il s'ouvre sinon sur celle qu'on a laissé en premier plan dans l'éditeur et il est facile d'avoir cliqué...
Pour la Combo :
Private Sub ComboBox1_Change()
Dim i%
LnS = ComboBox1.ListIndex + 1
If LnS > 0 Then
With [tblInfosemployé]
For i = 1 To 13
Controls("TextBox" & i).Value = .Cells(LnS, i + 1)
Next i
End With
Else
RéinitCtrl
End If
End Sub
Mais pour tester, il te faut renuméroter tes TextBox dans l'ordre des colonnes (NB- décalage de 1 : TextBox1 à 13 pour colonnes 2 à 14 du tableau, je dis du tableau, pas de la feuille !)
LnS est la ligne salarié sélectionnée, déclarée niveau module.
RéinitCtrl est une proc. d'effacement des TextBox. Ici l'effacement intervient si tu effaces la combo...
Dim LnS As Long
Sub RéinitCtrl()
Dim i%
For i = 1 To 13
Controls("TextBox" & i).Value = ""
Next i
LnS = 0
End Sub
A suivre...
Un immense merci MFerrand!!
Il m'a fallut du temps mais j'ai fini par y arriver!
Par contre, une dernière question si je peux abuser
Concernant mon bouton "modifier le salarié existant", mon code plate sur la ligne suivante :
Private Sub CommandButton2_Click()
Dim Ligne As Long
Dim I As Integer
If MsgBox("Confirmez-vous la modification de ce salarié ?", vbYesNo, "Demande de confirmation de modification") = vbYes Then
If Me.ComboBox1.ListIndex = -1 Then Exit Sub
Ligne = Me.ComboBox1.ListIndex + 2
Ws.Cells(Ligne, "D") = ComboBox1
For I = 1 To 13
If Me.Controls("TextBox" & I).Visible = True Then
Ws.Cells(Ligne, I + 2) = Me.Controls("TextBox" & I)
End If
Next I
End If
End Sub
Pourrais-tu m'éclairer?
Tu aurais dû attendre un petit peu plus car je te propose de procéder autrement, ainis que je l'avais déjà suggéré...
Pour l'erreur, il faut indiquer quelle erreur.
Je te signale aussi que si tu utilises le même fichier ton tableau commence ligne 6 en ce qui concerne les données !
Raison de plus pour utiliser le tableau, partie données dont la numérotation de lignes commencera à 1 ! (adressage relatif qui ne changera pas quelle que soit la position du tableau)
NB- Je réitère aussi mon incitation à te faire utiliser les balises Code !
Pardon je ne suis pas sûre de te suivre quand tu dis que tu proposais de procéder autrement
Je ne voulais pas t'embêter plus, j’espérais un peu m'en sortir toute seule...car pour le reste du formulaire, tout fonctionne...si ce n'est les deux boutons de contrôle
Je reprends pour ce qui des ajouts et modifs.
Tu as pu noter que la proc. CoùboBox1_Change que j'ai proposée initilise la variable module LnS à .ListIndex+1 qui correspond à une numérotation de ligne dans le tableau.
La proc. RéinitCtrl remet cette variable à 0.
Elle a donc une valeur >0 lorsque tu as sélectionné un salarié et que ses données ont été affectées aux TextBox, et vaut 0 si rien dans la Combo ou une saisie de nouveau salarié.
Qu'il s'agit d'ajout ou de modification, l'insertion des données est identique, seule la ligne diffère, la ligne qui suit les données du tableau en cas ajout, la ligne figurant en LnS en cas de modif. mais inutile d'avoir 2 procédures d'affectation :
Sub ValidationInfos()
Dim Lgn As Range, i%
Set Lgn = [tblInfosemployé].Rows(LnS)
Lgn.Cells(1, 1) = ComboBox1.Value
For i = 1 To 13
With Controls("TextBox" & i)
If .Value <> "" Then
Select Case i
Case 5, 6, 8, 9, 11, 13
If IsDate(.Value) Then
Lgn.Cells(1, i + 1) = CDate(.Value)
Else
Lgn.Cells(1, i + 1) = .Value
End If
Case Else
Lgn.Cells(1, i + 1) = .Value
End Select
End If
End With
Next i
ComboBox1.Value = ""
End Sub
Ma préférence serait allée à la constitution d'un tableau des données de la ligne à servir, affecté directement à la ligne voulue, mais tu as un peu trop de dates à contrôler lors de l'affectation... Donc on procède un peu autrement : on affecte la ligne d'insertion à une variable plage Lgn, et on sert ensuite les cellules de la ligne 1 de cette plage ! La valeur de la Combo ira en col. 1. Pour les TextBox, les valeurs des 1 à 13 iront dans les colonnes 2 à 14, mais on sépare le traitement de ceux susceptibles de contenir des dates (tu peux voir ça dans le code). Les dates doivent toujours être converties en données Date au sortir de TextBox qui ne contiennent par définition que du texte, pour éviter les surprises éventuelles d'inversions mois/jour (résultant d'une conversion sauvage par VBA, utilisant le format américain, la conversion explicite force à utiliser les paramètres FR).
Le changement de valeur de la Combo (mise à "") provoquera l'effacement des TextBox et la remise de LnS à 0.
Mais il convient pour un ajout que LnS qui est alors à 0 soit initialisée pour la nouvelle ligne :
Private Sub CommandButton1_Click()
If LnS > 0 Then
MsgBox "Le salarié affiché est déjà dans la base !", vbInformation, "Erreur"
Exit Sub
End If
If MsgBox("Confirmez-vous l'insertion de ce nouveau salarié ?", vbYesNo, _
"Demande de confirmation d'ajout") = vbYes Then
LnS = [tblInfosemployé].Rows.Count + 1
ValidationInfos
RéinitLst
End If
End Sub
Ce que va faire ta proc. bouton, qui vérifie avant que l'on n'est pas en mode modif (si LnS>0), qui initialise LnS (nb de lignes du tableau + 1), lance la validation, et à l'issue lance une réinitialisation de la liste de la Combo, après tri du tableau :
Sub RéinitLst()
Dim Lst
With [tblInfosemployé]
.Sort key1:=.Cells(1, 1), order1:=xlAscending, Header:=xlYes
Lst = .Resize(, 1).Value
End With
With ComboBox1
.Clear: .List = Lst
End With
End Sub
Pour la modif, c'est symétrique :
Private Sub CommandButton2_Click()
If LnS = 0 Then
MsgBox "Le salarié affiché n'est pas dans la base !", vbInformation, "Erreur"
Exit Sub
End If
If MsgBox("Confirmez-vous la modification de ce salarié ?", vbYesNo, _
"Demande de confirmation de modification") = vbYes Then
ValidationInfos
End If
End Sub
Vérification qu'on est bien en mode modif., validation identique, mais on ne réinitialise pas la Combo. En principe les modifs ne touchent pas le nom (à toi de voir par la suite...)
Cordialement.
Si je le fais c'est que cela ne m'embête nullement !
En proposant des éléments qui dérogeaient à l'orientation de ton code initial, il me fallait fournir les compléments...
Pour ton erreur, je ne peux voir ce qu'il en était si tu ne donnes pas le numéro d'erreur... Cela aurait pu écrire ailleurs que sur la bonne ligne sans provoquer d'erreur fatale (qui provoque un arrêt de l'exécution).
Je pense avoir a peu près compris ce que tu as fait, en revanche il reste un point bloquant : l'ajout d'un nouveau salarié se fait sur la première ligne non vide, or du coup il se positionne un peu n'importe ou.
Existe t-il un moyen de lui demander de placer un nouveau salarié en dernière ligne du tableau? Ou plus directement par ordre alphabétique, mais ça je n'y crois pas trop (ça serait le must, la cerise sur le gâteau
J'espère que l'ajout ne se fait pas sur une ligne non vide !
Ce qui est prévu : ajout en fin de tableau, sur un ligne vide donc, tableau retrié, ComboBox réinitialisée pour qu'on retrouve le nouveau salarié dans la liste à son rang alphabétique.
Cela ne se passe pas ainsi ?
Bonjour!
Je ne devais plus avoir les yeux en face des trous hier...car ce matin ça fonctionne
Merci encore pour ton aide précieuse! Je passe le post en résolu.
Bonne journée.
Sandrine
Bonjour,
Bonne continuation...
Les points clés :
- Si tableau Excel il est nommé, on utilise le nom, si pas tableau Excel on nomme la première colonne de la base (en dynamique, nom s'adaptant aux variations de taille), et on se retrouve dans les même conditions avec un nom à utiliser.
La référence à un nom de plage permet de se libérer de référence à la feuille (un souci en moins...), adressage plus rapide et plus facile à déterminer (nb- et le fait que la plage nommée ne couvre qu'une colonne au lieu de toutes ne limite pas mais au contraire offre plus de souplesse, .Offset et .Resize permettent toutes les possibilités de dimensionnement).
- Affectation quand on le peut (évaluation des difficultés qui pourraient compliquer cette méthode (notamment les problèmes de dates ou autres problèmes de conversion) au moyen d'un tableau auquel on affecte les données et qu'on affecte ensuite globalement à la ligne, en principe la méthode la plus rapide.
- Pour les dates, retenir qu'il faut toujours les convertir lors de l'affectation à une cellule, mais dans ton cas en passant par l'affectation à un tableau une première conversion n'empêchait pas VBA de reconvertir ensuite sans qu'on puisse l'empêcher... Dans un tel cas, une solution est à la fois de convertir en Date et convertir la date en nombre (Long), lequel ne peut plus être reconverti sauvagement, mais dans ce cas Excel n'assure plus le format de cellule date de façon automatique, il faut aller l'établir.
Bien que sur ce dernier point, j'aurais dû penser qu'un Tableau Excel en s'étendant étend les formats de cellule, et que l'on n'aurait peut-être pas eu à rétablir les formats, et dans ce cas l'utilisation d'un tableau aurait été gagnante...
A un prochaine, et bonne journée.
Merci pour tes conseils, que j'archive précieusement pour les réutiliser si besoin
Bonne journée!
Sandrine