Problème de programmation sur combox et sur spinbutton

Bonsoir à tous,

Débutant sur VBA, je me retrouve face à deux problèmes qui me font tourner en bourriques depuis quelques heures, et je n'arrive pas à me corriger.

Je cherche dans un premier temps à paramétrer une liste déroulante pour qu'elle m'affiche deux options dans un userform, problème rien ne s'affiche et je ne comprends pas pourquoi???

Voici mon code:

Je veux pouvoir avoir deux choix possible dans la liste déroulante qui s'affiche

Private Sub ComboBox2_Change()

Dim J As Long

Dim I As Integer

ComboBox2.ColumnCount = 1 'Pour la liste déroulante Position

ComboBox2.List() = Array(" ", "Décideur/chef de chantier", "Décideur/autre")

Set Ws = Sheets("BTP") 'Feuille BTP-Prospection

With Me.ComboBox1

For J = 2 To Ws.Range("N" & Rows.Count).End(xlUp).Row

.AddItem Ws.Range("N" & J)

Next J

End With

For I = 1 To 13

Me.Controls("TextBox" & I).Visible = True

Next I

End Sub

Mon second problème traite de la programmation d'un bouton de formulaire pour lancer un nouvel enregistrement sur un formulaire, et ayant un formulaire "vierge" face à moi, sans fermer le formulaire. Et je n'ai pas d'idée pour comment m'y prendre, est ce quelqu'un aurait une piste à m'indiquer pour me lancer?

Merci par avance pour votre aide pour un novice

Bonsoir,

Tu as intérêt à mettre le fichier si tu veux que quelqu'un te le remette sur pied !

La procédure Change du Combo présuppose que la liste y est et que tu as fait un choix. Définir la liste dans cette procédure... (tu n'y as pas beaucoup réfléchi... !)

Et mettre une espace dans la liste n'est pas très malin...

Y définir la propriété ColumnCount relève comme la liste d'un autre lieu. De plus c'est la propriété par défaut que tu n'as sûrement pas modifiée... Et as-tu déjà regardé la feuille de propriété qui sert à définir les propriétés que veux avoir à l'ouverture...

Comme ces éléments ne sont pas limitatifs, je te conseille vivement de mettre ton fichier...

Bonjour FERRAN,

Voici mon fichier, que j'essai de créer pour me faciliter la saisie de donnée.

Mais j'avoue avoir du mal à te suivre, qu'entends tu par définir la liste dans la procédure?

Définir la liste dans la procédure Change de la ComboBox ! Cela dit que c'est dans la procédure déclenchée par le choix d'une entrée dans la liste que tu mets une commande pour affecter une liste... mais si la liste n'y est pas tu ne provoqueras pas le déclenchement (du moins par sélection), il y a une petite contradiction à vouloir affecter la liste après qu'on est censé avoir fait un choix dans ladite liste.

Je vais regarder ton fichier.

Le Userform s'ouvre, c'est déjà ça, mais ça s'arrête là ! On aurait du mal à faire plus confus !

Au point que je me demande ce que tu veux faire précisément !

J'aimerais donc quelques détails utiles.

Que doit-il s'afficher dans ComboBox1 au démarrage ?

Au-delà des erreurs de syntaxe, tu y mets un prénom, que tu remplaces immédiatement par rien ! et substitution du type d'entreprise après sélection...

Toutes ces manoeuvre étant bien inutiles dans tous les cas, étant donné que visiblement la sélection d'un élément dans la liste est normalement destinée à provoquer l'affichage de l'enregistrement dans les TextBox (ce qui n'est pas codé).

Il s'agit donc de savoir si c'est l'entreprise que l'on sélectionne ou le contact ?

J'opterais logiquement pour l'entreprise, à partir de quoi on peut afficher toutes les données correspondantes mais il faudrait en être sûr.

Problème de ComboBox2 : ce n'est pas la liste, c'est que tu affectes la données correspondante en colonne A, laquelle ne fait pas partie de ton tableau... Il y a là un point à éclaircir.

Par ailleurs, si tu mets en place un tableau Excel pour ne pas l'utiliser, il n'était pas utile de faire ainsi. Il est là, autant s'en servir !

Il faut aussi dès maintenant éviter de recopier n'importe quelle commande sans te demander à quoi cela va effectivement servir !

Si tu mets en place un Userform pour saisir et modifier tes données, ce n'est en principe pas pour que l'utilisateur l'ouvre, le mette de côté et aille saisir directement dans le tableau ! ou qu'il aille musarder ailleurs dans le fichier pendant que le formulaire est ouvert !

Accoler vbModeLess à la commande d'ouverture semble devenu à la mode, mais c'est injustifié la plupart du temps, sinon carrément idiot !

Si la possibilité d'ouvrir en non modal (qui d'ailleurs n'existait pas à l'origine) a été introduite, c'est pour répondre à quelques besoins spécifiques (notamment affichage de messages temporaires...) mais l'utilisation habituelle d'un Userform exige qu'il soit modal (que l'utilisateur aille au bout de l'opération entamée avant de passer à autre chose).

Et il serait bon aussi d'avoir quelques idées claires : les caractéristiques fixes se programment à la conception, dans la fenêtre de propriétés, on définit ainsi les propriétés par défaut des contrôles, celles qu'ils auront toujours à l'ouverture du Userform ; on réserve l'usage du code pour les définir lorsque cela peut changer selon le contexte, et lorsqu'il faut les modifier en cours d'exécution. En ayant ces notions bien présentes, les choses deviennent plus faciles à organiser.

J'attends tes précisions sur les ComboBox1 et 2, indispensables pour arranger l'ensemble, sur lesquels je ne peux décider quel doit être leur contenu.

Rebonjour,

Un examen un peu plus approfondi, m'incite à considérer que ComboBox1 est destinée à afficher les contacts. Ensuite la sélection d'un contact permet d'afficher les autres données relatives à ce contact.

Donc première étape : une procédure Initialize qui alimente les Comb à l'ouverture :

Private Sub UserForm_Initialize()

ComboBox1.RowSource = [Tableau1].Offset(, 3).Resize(, 2).Address

ComboBox2.List() = Array("Décideur/chef de chantier", "Décideur/autre")

End Sub

On utilise RowSource pour Combo1 à qui on envoie l'addresse d'une plage de Tableau1 à 2 colonnes (nom et prénom contact).

La propriété ColumnCount est définie à 2 dans la fenêtre de propriétés.

On utilise List pour Combo2 à qui on envoie un tableau.

A la sélection d'un contact dans Combo1, on prélève les données correspondantes dans le tableau pour les affecter aux TextBox et à Combo2 :

Private Sub ComboBox1_Change()
    Dim i%, n%
    n = ComboBox1.ListIndex + 1
    If n > 0 Then
        For i = 1 To 12
            Controls("TextBox" & i).Value = [Tableau1].Cells(n, i).Value
        Next i
        ComboBox2.Value = [Tableau1].Cells(n, 13).Value
        TextBox13.Value = [Tableau1].Cells(n, 14).Value
    Else
        For i = 1 To 13
            Controls("TextBox" & i).Value = ""
        Next i
        ComboBox2.ListIndex = -1
    End If
End Sub

On a fourni une liste ordonnée à Combo1, donc on aura une correspondance exacte entre une ligne de Tableau1 et la valeur de ListIndex+1 lors de la sélection. On recueille ce numéro de ligne (dans Tableau1, pas dans la feuille) dans une variable n.

Les TextBox sont dans le même ordre que les colonnes du tableau : on peut donc utiliser une boucle pour affecter les valeurs (seul Combo2 vient casser la continuité...)

En cas de changement de sélection, tout cela se met à jour. Et il faut évidemment prévoir le cas où l'on efface la sélection dans Combo1, cas où les TextBox doivent être aussi effacées.

A ce stade, cela fonctionne...

Pour la suite, il y a des interrogations auxquelles il faut répondre.

D'abord le SpinButton : il semble qu'il doive servir à passer d'un enregistrement à l'autre, soit à faire varier la sélection de ComboBox1 sans dérouler la liste (sinon je ne vois pas à quoi il peut servir ?)

Si c'est bien le cas, il est mal placé en bas, car sa place serait plus logique au-dessous de la Combo, étant utilisé conjointement.

Les paramètres doivent également être en rapport avec la liste : la valeur doit être indexée sur le ListIndex de Combo1 (ajout dans ce sens à faire à la proc. Change), et lorsqu'on modifiera cette valeur dans le Spin, elle doit sur répercuter sur Combo1 (proc. Change du SpinButton à écrire). Le Min doit donc être fixé à -1 (correspondance avec les valeurs possibles de ListIndex. Et le Max doit être modifié dynamiquement en fonction de la taille de la liste (instructions à rajouter dans l'Initialize).

Fonctionnement du SpinButton à confirmer donc !

Par ailleurs, 2 boutons permettent respectivement d'ajouter un contact ou de le modifier. Le fait d'avoir 2 boutons est sans doute une sécurité, mais à ce moment-là pour qu'elle soit complète, il conviendrait que seul l'un des boutons soit actifs simultanément selon que l'on se trouve en ajout ou modification, ce qui pourrait être obtenu par 2 OptionButton permettant de choisir un mode ou l'autre.

Il y a d'autres moyens : 2 boutons Aouter / Modifier pour lancer le formulaire. Selon le bouton activé on sera placé dans un mode ou l'autre. Ou bien message demandant quelle option est retenue avant d'ouvrir... Mais si on veut pouvoir modifier l'option en cours d'opération, il faut pouvoir opter dans le formulaire.

Une autre solution serait de faire détecter automatiquement par une procédure dans quel cas on se trouve. Auquel cas, un seul bouton de validation est requis puisqu'il sera défini automatiquement s'il s'agit d'un ajout ou d'une modif.

Dans un tel cas, il faut aussi savoir si les champs désignant le contact (nom et prénom) sont sans doublon possible ou non.

Bref, définir les règles avec lesquelles on veut fonctionner, et on pourra programmer de façon qu'elles s'appliquent.

A suivre...


Le fichier en l'état pour que tu aies une idée des modifications apportées pour l'ouverture...

Le code est épuré de tout ce qui était sans objet pour la suite, seuls demeurent les fragments susceptibles d'être réutilisés.

En l'état, on ne peut qu'ouvrir et manipuler les Combo. Pour un formulaire fonctionnel il faut poursuivre la programmation des autres éléments selon les options retenues.

Cordialement.

Bonjour MFERRAN,

Tout d'abords, un grand merci pour ta réponse qui m'éclaire grandement sur mes problèmes de formulaire et de programmation. Je passe trop d'étapes sans me poser de question. Et du coup je me complique la vie sur beaucoup de chose., (je pense au tableau et à la saisie de donnée que je m'étais imaginée, ou bien encore les caractéristiques fixes du formulaire ) .

En ce qui concerne la combobox1, il s'agit bien d'afficher mes contacts ainsi que leurs données associées pour retrouver leurs fiches plus facilement.

La combobox 2, me sert à affilié à mon contact un statut que je lui défini quand je le rencontre en fonction de son pouvoir dans l'entreprise.

En ce qui concerne, le spinbutton, il a en effet pour but de passer d'un enregistrement à l'autre. Je l'avais mis en bas de mon formulaire en me référant à mon expérience Access, où cela influençait peu le fonctionnement de mes formulaires, juste l'aspect pratique de la saisie.

Dans mon esprit, l'utilisation de mes 3 boutons servaient de la façon suivante:

_Nouveau contact:

Ouvrir une nouvelle saisie sur le formulaire avec l'ensemble de mes éléments vides.

-Enregistrer contact:

Enregistrer la saisie d'un nouveau contact.

-Quitter:

Fermer le formulaire.

La solution préférable dans mon esprit, serait en effet de mettre un bouton actif puis l'autre, toujours dans cette optique de sécurité.

Mais du coup, comment fait-on pour programmer ces éléments?

Bonsoir,

Le SpinButton sera mieux placé sous ComboBox1 où tu as de l'espace vide et où tu pourras voir immédiatement l'effet sur le Combo.

Je note ton maintien des deux boutons. Il me semble avoir évoqué les différentes possibilités à cet égard dans mon dernier post...

Le critère de différenciation est qu'il n'y aura rien dans ComboBox1 si tu es en ajout.

On peut inclure une vérification supplémentaire s'il ne doit pas y avoir de doublon dans les contacts... (toi seul peut le dire).

A suivre donc (mais pas à cette heure-ci !)

Bonjour,

J'aurais dû normalement te livrer les compléments ajoutés et les modifications de ce qui avait déjà été fait.

Mais mon réveil tardif du jour m'a un peu décalé...

J'en suis à passer à la préparation du repas, je reviendrai donc après pour te fournir le fichier au stade où il est parvenu, avec toutes les explications utiles.

Je commence par une petite difficulté qui m'a fait modifier l'alimentation de ComboBox1. Difficulté que je n'avais pas encore rencontrée, mais je n'ai sans doute jamais eu la configuration exacte utilisée dans ton Userform...

Cela tient à ce que la liste de ComboBox1 est définie par une plage, mais simultanément la sélection dans le Combo fait également partie du contenu de l'enregistrement affecté aux TextBox. Pas de problème jusque là, mais lorsque l'on valide et affecte le contenu des TextBox à la feuille, même si le nom du contact n'est pas modifié, la réaffectation interagit avec la liste du Combo et déclenche la procédure Change, laquelle aboutissait à réaffecter les valeurs des TextBox, donc à annuler les modifications se produisant sur les colonnes au-delà de la 4e (nom du contact)...

Une fois identifiée la cause du phénomène, la solution consistait à dissocier la liste de la plage pour éviter cet effet en retour. J'ai donc fait un retour pour alimenter la liste à la propriété List, en lui affectant un tableau de valeurs, tableau auxquel les valeurs de la plage étaient préalablement affectées.

Le premier prolongement de la programmation du Userform consistait à établir le lien fonctionnel entre le SpinButton et ComboBox1.

Je n'ai pas finalement modifié la position du SpinButton, car elle ne nuisait pas du tout à son utilisation. Cependant tu pourras peut-être améliorer la disposition des contrôles dans le Userform qui comporte pas mal d'espaces vides... Le Spin te permet en fait de naviguer dans la liste sans utiliser la liste déroulante, ce qui peut être assez confortable...

Pour le coupler avec le Combo, le Min est établi à -1 et la Value initiale à -1 également : ces 2 propriétés sont mises "en dur" dans la fenêtre de porpriété (le Spin aura toujours ces paramètres à l'ouverture).

Le Max par contre doit s'adapter à la taille de la liste du Combo : on le fixe donc au démarrage à ListCount-1, ce qui met Spin...Value en correspondance avec Combo...ListIndex.

Parallèlement, à l'ouverture aucune sélection n'est faite, le bouton Ajout peut être actif, mais le bouton Modifier doit être inactif.

Ce qui conduit à une modification de la procédure Initialize :

Private Sub UserForm_Initialize()

    Dim lc()
    lc = [Tableau1].Offset(, 3).Resize(, 2).Value
    ComboBox1.List() = lc
    ComboBox2.List() = Array("Décideur/chef de chantier", "Décideur/autre")
    SpinButton1.Max = ComboBox1.ListCount - 1
    CommandButton3.Enabled = True
    CommandButton1.Enabled = False
End Sub

Il convenait également que la proc. Change du Combo soit adaptée pour d'un côté aligner la valeur du SpinButon sur son ListIndex et d'autre part basculer le bouton Modifier en actif et Ajout en inactif dès lors qu'une sélection est faite dans le Combo.

Private Sub ComboBox1_Change()
    Dim i%, n%
    n = ComboBox1.ListIndex + 1
    SpinButton1.Value = n - 1
    If n > 0 Then
        For i = 1 To 12
            Controls("TextBox" & i).Value = [Tableau1].Cells(n, i).Value
        Next i
        ComboBox2.Value = [Tableau1].Cells(n, 13).Value
        TextBox13.Value = [Tableau1].Cells(n, 14).Value
        CommandButton3.Enabled = False
        CommandButton1.Enabled = True
    Else
        RéinitUsf
    End If
End Sub

Le code correspondant à l'absence de sélection (ListIndex = -1) est lui reporté dans une procédure auxiliaire, qui sera également utilisée après validation d'ajout ou de modif. pour effacer les TextBox...

Sub RéinitUsf()
    Dim i%
    For i = 1 To 13
        Controls("TextBox" & i).Value = ""
    Next i
    ComboBox2.ListIndex = -1
    CommandButton3.Enabled = True
    CommandButton1.Enabled = False
End Sub

L'ajustement inverse du ListIndex du Combo sur la Valeur du Spin lorsqu'on agit sur ce dernier, est assuré par la Proc. Change du Spin :

Private Sub SpinButton1_Change()
    Dim n%
    n = SpinButton1.Value
    If ComboBox1.ListIndex <> n Then ComboBox1.ListIndex = n
End Sub

Un dysfonctionnement de mon navigateur m'a empêché d'écrire la dernière phrase du post précédent.

La condition dans la procédure évite des répétitions d'exécution de la même procédure. Ce n'est pas gênant dans la mesure où il ne s'ensuit aucune modification intempestive mais si on peut l'éviter facilement, autant le faire.

Venons-en à l'affectation de la saisie validée à la feuille.

On place l'affectation des valeurs dans une procédure annexe, car elle est commune à l'ajout et à la modif. et il est donc inutile de répéter le même code pour chacun des boutons :

Sub MàJContact(n As Integer)
    Dim i%
    With [Tableau1]
        For i = 1 To 11
            .Cells(n, i).Value = Controls("TextBox" & i).Value
        Next i
        .Cells(n, 12).Value = DateValue(TextBox12.Value)
        .Cells(n, 13).Value = ComboBox2.Value
        .Cells(n, 14).Value = TextBox13.Value
    End With
End Sub

Elle est symétrique de l'affectation des valeurs aux TextBox, à un détail près : TextBox12 contient une date, et ce qu'on affecte c'est sa valeur date au lieu de la chaîne texte qui la représente, ceci afin d'éviter son interception par VBA en tant que texte pour l'interpréter en date au format américain (mois-jour-année), provoquant une inversion mois/jour chaque fois que les deux sont inférieur à 13...

Tu as d'ailleurs de la chance car j'ai rencontré plusieurs fois des cas où cette méthode ne suffit pas à empêcher VBA d'inverser mois et jour...

On peut passer plus rapidement sur les procédures des boutons.

J'ai considéré que le nom du contact et celui de l'entreprise constituaient des saisies obligatoires. Le contact au moins, servant d'identifiant de l'enregistrement était requis. On peut évidemment en ajouter d'autres et bloquer la validation tant que certaines valeurs n'ont pas été saisies...

Lors d'une modification, l'action sur le bouton entraîne la vérification des champs 2 (entreprise) et 4 (nom contact). En cas d'absence les valeurs antérieures (nécessairement existantes) sont rétablies.

La même vérification en cas d'ajout est bloquante, l'utilisateur doit saisir ces données.

Dans les deux cas, la procédure définit la ligne (nouvelle ligne en cas d'ajout) et lance l'affectation.

Ensuite, en cas de modif, on efface la Combo (ListIndex à -1), mais en cas d'ajout on réaffecte la liste qui a été modifiée et on recalcule le Max du Spin.

Et dans les deux cas, on fait appel à la procédure d'effacement pour réinitialiser le Userform, prêt pour une nouvelle saisie ou modification.

Tu disposes là d'une base fonctionnelle. Il y manque peut-être la Suppression d'un contact (bouton Supprimer à ajouter ou autre méthode ?). Ensuite tu peux agrémenter si le besoin s'en fait sentir par des procédure de contrôle de la saisie au niveau de chaque TextBox pour bloquer des saisies manifestement fausses ou opérer des corrections automatiques (mettre le nom en majuscules par exemple...)

Cordialement.

Bonjour MFERRAN,

Un grand merci pour votre aide inestimable qui me fait gagner un temps précieux dans mes recherches et ma formation sur l'utilisation d'Excel.

j'ai désormais un retour d'expérience et une base de travail qui vont me permettre de continuer à me former en VBA en toute pérennité grâce à cet outils que vous m'avez aidé à construire .

Un grand bravo pour ce site et sa communauté

Bonne continuation...

Rechercher des sujets similaires à "probleme programmation combox spinbutton"