IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Macros et VBA Excel Discussion :

ComboBox : Rendre la saisie impossible si celle-ci ne figure pas dans la propriété List


Sujet :

Macros et VBA Excel

  1. #1
    Membre Expert
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 817
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 817
    Billets dans le blog
    10
    Par défaut ComboBox : Rendre la saisie impossible si celle-ci ne figure pas dans la propriété List
    Préambule :

    Cette contribution fait suite à ce sujet, dont la question est :
    Je souhaiterais empêcher toute saisie si le texte entrant dans la ComboBox ne correspond pas à la liste initiale du contrôle.
    Les différentes méthodes décrites dans cette discussion ne sont, dans l'état, soit, pas fiables, soit, pas génériques, soit incomplets.

    Je me permets donc de décrire ici une autre méthode, pour le cas où, l’internaute que vous êtes, ne trouverait pas son bonheur dans la susdite discussion.

    1. Description du contrôle ComboBox :
      Un contrôle ComboBox est composé de deux éléments :
      • Une partie texte (similaire à un contrôle TextBox) qui est la zone de saisie du contrôle,
      • Une partie liste (similaire à un contrôle ListBox) qui est la zone de liste (déroulante) de ce contrôle.

      Cette description est à conserver dans un coin de votre mémoire, nous nous en servirons plus tard dans cette contribution.

    2. Les propriétés intéressantes :
      La totalité de ces détails sont issus de l'aide VBA (qui en comporte encore de nombreux, n'hésitez pas à la consulter).
      Je n'invente donc rien.
      • La propriété Style.
        Pour un contrôle ComboBox, spécifie de quelle façon l'utilisateur va utiliser le contrôle.
        Les valeurs de fmStyle sont les suivantes :
        • fmStyleDropDownCombo (Valeur : 0) : Le contrôle ComboBox se comporte comme une liste modifiable déroulante.
          L'utilisateur peut saisir une valeur dans la zone d'édition ou en sélectionner une dans la liste déroulante (par défaut).
        • fmStyleDropDownList (Valeur : 2) : Le contrôle ComboBox se comporte comme une zone de liste.
          L'utilisateur doit choisir une valeur dans la liste.
      • La propriété MatchEntry.
        Nous ne l'utiliserons pas ici, mais elle mérite d'être connue.
        Renvoie ou définit une valeur indiquant la façon dont un contrôle ListBox ou ComboBox fait des recherche dans ses listes pendant la saisie de l'utilisateur.
        • fmMatchEntryFirstLetter (Valeur : 0) : Correspondance de base. Le contrôle recherche l'entrée suivante qui commence par le caractère saisi.
          La frappe répétée de la même lettre parcourt toutes les entrées commençant par cette lettre.
        • fmMatchEntryComplete (Valeur : 1) : Correspondance étendue.
          Pour la frappe de chaque caractère, le contrôle recherche une entrée correspondant à tous les caractères saisis (par défaut).
        • fmMatchEntryNone (Valeur : 2) : Aucune correspondance.
      • La propriété MatchRequired.
        Spécifie si une valeur saisie dans la partie texte d'un contrôle ComboBox doit correspondre à une entrée de la partie liste existante du contrôle. L'utilisateur peut taper des valeurs non correspondantes, mais ne peut pas quitter le contrôle sans qu'une valeur correspondante soit saisie.

    3. Démarche :
      • Premier cas : Utilisation de la liste comme une liste déroulante modifiable, la propriété Style réglée sur fmStyleDropDownCombo.
        Ici, l’utilisateur peut saisir exactement ce qu’il souhaite.
        Pour obtenir le résultat escompté ici, il nous faut donc ajouter une autre propriété l’empêchant de faire n’importe quoi. La propriété MatchRequired est idéale pour cela : L'utilisateur peut taper des valeurs non correspondantes, mais ne peut pas quitter le contrôle sans qu'une valeur correspondante soit saisie.
        Parfait !
        Le code est donc :
        Code : Sélectionner tout - Visualiser dans une fenêtre à part
        1
        2
        3
        4
           With ComboBox1
              .Style = fmStyleDropDownCombo
              .MatchRequired = True
           End With
        Ce code est fonctionnel, mais voilà, l’utilisateur se plaint qu’il n’y a pas de vérification en cours de saisie et qu'en cas d'erreur, il ne le sait qu'à la fin...

      • Second cas : Utilisation de la liste comme une zone de liste, la propriété Style réglée sur fmStyleDropDown.
        Eh bien, dans ce cas, rien à ajouter. Le code est donc :
        Code : Sélectionner tout - Visualiser dans une fenêtre à part
        1
        2
        3
           With ComboBox1
              .Style = fmStyleDropDownList
           End With
        Le gros bémol de cette méthode réside dans le fait que, dès que l’utilisateur saisi un caractère correct, la zone de texte est complétée par le premier item correspondant dans la liste.
        L’utilisateur ne visualise plus ou il en est de sa saisie.
        Les contrôles ComboBox ne disposant pas des propriétés SelLenght et SelStart, ce souci ne peut être résolu.

    4. Particularité à prendre en compte absolument :
      Ces codes, extrêmement simples, ne sont pas applicables tels quels selon les types de données entrées dans la liste.
      J’en reviens à ma description.
      La zone de saisie renvoie systématiquement une donnée de type String (VarType = 8).
      La zone de liste, elle, est de type Variant/Variant (VarType = 8204 [8192 (Variant Tableau) + 12 (Variant)].
      Lorsque cette liste contient des items numériques, des dates, des valeurs de type Currency (etc…), le type de chacun de ses items est Variant/Type de l’item.
      Soit, pour une date, de type Variant/Date.

      Lors de l’utilisation des codes donnés plus haut, si vos données ne sont pas de type String, la comparaison entre la zone de texte et la zone de liste ne trouvera aucune correspondance.
      Il convient donc, pour tous les types de données cités ci-dessous, de convertir toute la liste avant de l’attribuer au contrôle ComboBox.

      Types de données à convertir absolument :
      Integer
      Long
      Single
      Double
      Currency
      Date
      Byte
      LongLong
    5. Codes à appliquer pour ces cas :
      Note : Je ne m’attarde pas ici sur les variables tableaux et utilise des bornes figées. A vous d’adapter cela à votre contexte.

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      Private Sub UserForm_Activate()
      Dim L(364) As String, v As Variant, i As Long
         ' transfert des données en mémoire
         v = Range("C1:C365").Value
         ' Conversion des données en String
         For i = 1 To 365
            L(i - 1) = v(i, 1)
         Next
         With ComboBox1
            .List = L
            .Style = fmStyleDropDownCombo
            .MatchRequired = True
         End With
      End Sub
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      Private Sub UserForm_Activate()
      Dim L(364) As String, v As Variant, i As Long
         ' transfert des données en mémoire
         v = Range("C1:C365").Value
         ' Conversion des données en String
         For i = 1 To 365
            L(i - 1) = v(i, 1)
         Next
         With ComboBox1 
            .List = L
            .Style = fmStyleDropDownList
         End With
      End Sub
    6. Cas très particulier :
      L'alimentation du contrôle ComboBox via sa propriété rowSource.
      Cela ne pose pas de problème pour des données numériques ou du texte. Les codes donnés ci-dessus restent fonctionnels.
      Cependant, si vous entrez, par cette propriété, des données de type Date, dans votre ComboBox, ces codes ne fonctionneront pas, les Dates étant stockées sous forme numérique dans la feuille.


    Il existe très certainement des petits soucis, dus principalement à une méconnaissance de l'utilisation de ce contrôle, mais vous devriez pouvoir satisfaire vos utilisateurs.
    Certaines touches sont appréciables : Echap, flèche vers le haut (ou vers le bas)...


    A vous lire.

  2. #2
    Inactif  

    Homme Profil pro
    cuisiniste
    Inscrit en
    Avril 2009
    Messages
    15 374
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cuisiniste
    Secteur : Bâtiment

    Informations forums :
    Inscription : Avril 2009
    Messages : 15 374
    Billets dans le blog
    8
    Par défaut re
    Bonjour pijaku

    la version fmStyleDropDownCombo avec MatchRequired n'empeche pas la saisie on a un message de la combobox au exit quand un autre control prends le focus

    la version fmStyleDropDownList bloque tout bonnement la saisie apres la 1 ere touche
    de plus si tu tape une premiere lettre dont aucun item ne commencant par cette lettre c'est l'item0 qui selectionné

    le code que j'ai utilisé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    Private Sub UserForm_Activate()
        Dim L(364) As String, v As Variant, i As Long
        ' transfert des données en mémoire
        v = Range("C1:C365").Value
        ' Conversion des données en String
        For i = 1 To 365
            L(i - 1) = v(i, 1)
        Next
        With ComboBox1
            .List = L
            .Style = fmStyleDropDownCombo
            .MatchRequired = True
        End With
        With ComboBox2
            .List = L
            .Style = fmStyleDropDownList
        End With
    End Sub
    'visuel sur pour l'item selectionné 
    Private Sub ComboBox1_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
    ComboBox1.DropDown
    End Sub
    Private Sub ComboBox2_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
    ComboBox2.DropDown
    End Sub
    liste des mots utiliser en colonne"C" pour tester ton code

    poire
    pomme
    orange
    orizon
    cerise
    cerre
    tomate
    tomber


    le modele avec matchrequired peu etre interessant pour bloquer l'utilisateur tant que la value n'est pas valide (pas de code le msgbox fait tout tout seul)
    par contre en ce qui concerne le bloquage de saisie dynamique si aucun item ne correspond comme je l'ai répété plusieurs fois dans l'autre discussion ca ne fonctionne pas
    voir meme ici en l'occurence ton modele avec fmStyleDropDownList est carrément bloquant des la premiere lettre bonne ou mauvaise
    capture animée a l'appui si tu veux

    perso je fait ca avec une variable static dans l'evenement keyup
    mes fichiers dans les contributions:
    mail avec CDO en vba et mail avec CDO en vbs dans un HTA
    survol des bouton dans userform
    prendre un cliché d'un range

    si ton problème est résolu n'oublie pas de pointer : : ça peut servir aux autres
    et n'oublie pas de voter

  3. #3
    Membre Expert
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 817
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 817
    Billets dans le blog
    10
    Par défaut
    Bonjour Patrick,

    la version fmStyleDropDownCombo avec MatchRequired n'empeche pas la saisie on a un message de la combobox au exit quand un autre control prends le focus
    Pour le contrôle en cours de saisie qui n'est pas fait, j'en parle dans le point 3 :
    La propriété MatchRequired est idéale pour cela : L'utilisateur peut taper des valeurs non correspondantes, mais ne peut pas quitter le contrôle sans qu'une valeur correspondante soit saisie.
    Ta ComboBox réagit exactement comme, sur une feuille de calcul, une liste de validation avec message d'alerte etc...
    Tu pourras, de la même manière qu'une liste de validations de données, sortir de la ComboBox, si et seulement si :
    > elle est vide (appuie sur Echap pour la vider),
    > elle comporte une donnée valide.
    ______________________________________________________________________________________


    la version fmStyleDropDownList bloque tout bonnement la saisie apres la 1 ere touche
    Cette version ne bloque rien du tout.
    Si tu veux recommencer ta saisie, appuie sur Echap, puis sur un caractère valide...

    Préambule à ce qui suit :
    > je disposes de la version Excel 2010,
    > supprime de tes essais les événements que tu as ajouté (seule manière pour tester partout de la même façon) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    'visuel sur pour l'item selectionné 
    Private Sub ComboBox1_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
    ComboBox1.DropDown
    End Sub
    Private Sub ComboBox2_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
    ComboBox2.DropDown
    End Sub
    Tu pourras observer deux comportements différents, ou pas, selon ... les capacités de ta version Excel à s'adapter à ton utilisation...

    Premier comportement :
    Avec ta liste de mots utilisés pour tester :
    - saisir "a" :=> va "sélectionner" pomme (ListIndex = 0) ****
    - l'utilisateur se rend alors compte de cette erreur, :=> il appuie sur Echap
    - note bien que pomme est alors toujours "sélectionné" (ou pas... cf second comportement), mais que la propriété ListIndex = -1...
    - saisir "o" :=> va "sélectionner" orange

    C'est ce comportement, que tu sembles ne pas apprécier (à juste titre ou pas), qui est observé.
    Si tu veux ne plus rien avoir de "sélectionné" dans ta ComboBox, utilises l'astuce de Pierre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        With ComboBox2
            .List = L
            .Style = fmStyleDropDownList
            .AddItem "", 0
        End With
    ou alors une autre astuce, placer du code, même inutile (tu pourras virer le MsgBox, voir tout le code), dans l'événement Change().
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Private Sub ComboBox1_Change()
    Dim i As Long
       i = ComboBox1.ListIndex
       MsgBox i 
    End Sub
    En faisant exactement les mêmes gestes que ci-dessus, j'observe ce :
    Second comportement :
    Avec ta liste de mots utilisés pour tester :
    - saisir "a" :=> va "sélectionner" pomme (ListIndex = 0)
    - l'utilisateur se rend alors compte de cette erreur, :=> il appuie sur Echap
    - note bien alors que pomme n'est alors plus "sélectionné" ET que le contrôle de saisie de la ComboBox s'est vidé (ou pas... si ta version d'Excel ne s'adapte pas...)
    - saisir "o" :=> va "sélectionner" orange


    Je ne sais pas quel code (l'astuce de Pierre ou le ComboBox_Change()) a fait en sorte que mon Excel réagit maintenant systématiquement selon le second comportement, mais c'est un fait.

    Pour conclure, les deux méthodes développées ici fonctionnent.
    Il suffit de connaitre les quelques touches utiles à la bonne utilisation du contrôle ComboBox.
    En l'occurrence : Echap et les flèches (vers le haut et le bas).


    ****PS1 : les guillemets autour de sélectionné.
    J'ai utilisé dans mes descriptions des comportements ci-dessus, des guillemets autour de chaque "sélectionner".
    Ce n'est pas anodin.
    La notion de sélection dans un contrôle ComboBox n'intervient qu'au moment de l'événement click().
    Oui, mais, (allez-vous me dire en bon chicaneur que vous êtes), l'événement Click() n'est jamais déclenché, puisque l'on fait tout au clavier!
    Et bien non...
    Voyons l'aide VBA à propos de la propriété MatchEntry (que nous n'utilisons pas) :
    Remarques

    La propriété MatchEntry recherche des entrées à partir de la propriété TextColumn d'un contrôle ListBox ou ComboBox.

    Le contrôle recherche dans la colonne identifiée par la propriété TextColumn une entrée correspondant à la saisie de l'utilisateur.
    Lorsqu'une correspondance est trouvée, la ligne contenant la correspondance est sélectionné, le contenu de la colonne est affiché et celui de sa propriété BoundColumn devient la valeur du contrôle. Si la correspondance n'est pas ambiguë, le résultat de la correspondance déclenche l'événement Click.

    Le contrôle déclenche l'événement Click dès que l'utilisateur tape une suite de caractères correspondant exactement à l'entrée de la liste.
    Pendant que l'utilisateur tape, l'entrée est comparée à la ligne courante de la liste et à la ligne suivante. Lorsque l'entrée ne correspond qu'à la ligne courante, la correspondance est non ambiguë.

    Dans Microsoft Forms, ceci est vrai que la liste soit ou non triée. Cela signifie que le contrôle trouve la première occurrence qui correspond à l'entrée en fonction de l'ordre des éléments de liste.
    Pour vous en assurer, dans un nouveau projet, placer un petit userform avec une combobox dedans et ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Private Sub ComboBox1_Click()
       Range("A" & Rows.Count).End(xlUp).Offset(1, 0) = "clic"
    End Sub
     
    Private Sub UserForm_Activate()
        Dim L(364) As String, d As Date, i As Long
        d = CDate("01/01/2018")
        For i = 1 To 365
            L(i - 1) = CStr(d)
            d = DateAdd("d", 1, d)
        Next
        With ComboBox1
            .List = L
            .Style = fmStyleDropDownList
        End With
    End Sub
    Lancez l'userform (pas trop loin) en vous assurant de pouvoir visualiser la feuille active.
    Notez que la combobox est remplie des dates de cette année.

    Tapez, caractère après caractère : 01/05/2018
    Le clic va se déclencher 2 fois :
    1. après la saisie du 1 :=> pour lui, la correspondance n'est pas ambiguë,
    2. après le 5 :=> ici la correspondance est parfaite (unique), donc il n'y aura plus d'événement Click (sauf à effacer votre saisie).


    PS2 : Lorsque je parle d'adaptation de la part d'Excel, je ne peux en avoir aucune certitude, les ingénieurs MicroSoft étant peu bavard.
    Cependant, il existe comme cela des phénomènes inexpliqués.
    Un second exemple (bien loin de ce sujet) serait le nombre d'areas possibles dans une feuille qui augmente en cas de besoin...


    Bonne suite

  4. #4
    Membre extrêmement actif
    Homme Profil pro
    Inscrit en
    Septembre 2013
    Messages
    1 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Septembre 2013
    Messages : 1 369
    Par défaut
    Bonjour,

    Il y a aussi la saisie intuitive qui ne permet que la saisie d'un élément dans une liste.

    MacthEntry : None

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    Option Compare Text
    Dim Tbl()
    Private Sub UserForm_Initialize()
      Set f = Sheets("BD")
      Tbl = f.Range("A2:A" & f.[A65000].End(xlUp).Row).Value
      Me.ComboBox1.List = Tbl
    End Sub
     
    Private Sub ComboBox1_Change()
      Set d1 = CreateObject("Scripting.Dictionary")
      tmp = UCase(Me.ComboBox1) & "*"
      For Each c In Tbl
        If c Like tmp Then d1(c) = ""
      Next c
      Me.ComboBox1.List = d1.keys
      Me.ComboBox1.DropDown
    End Sub
     
    Private Sub ComboBox1_Click()
      ActiveCell = Me.ComboBox1
      Unload Me
    End Sub
    Boisgontier
    Fichiers attachés Fichiers attachés

  5. #5
    Membre Expert
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 817
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 817
    Billets dans le blog
    10
    Par défaut
    Bonjour Jacques,

    Je vois plusieurs inconvénients à utiliser une telle méthode.

    1. Elle n'empêche nullement une saisie ne faisant pas partie de la liste initiale :
      C'est plutôt une bonne chose que d'inciter l'utilisateur a avoir un bon comportement.
      Cependant, dans ce cas, cela nécessite tout de même un second contrôle en sortie de formulaire.
    2. Elle oblige à remplir à nouveau la liste de la ComboBox en cas saisie répétée d'un même formulaire (sans le Unload),
      Rien d'important, une ligne de code à ajouter, je te l'accorde.
    3. Elle utilise un Objet Dictionary non-disponible chez tous les utilisateurs.
      Peut-être problématique... Mais facilement modifiable en utilisant une Collection.
    4. Quid d'un contrôle ComboBox Multi colonnes...

    Je vais donc fourguer ton code modifié, transformé en petite fonction, dans mon grenier VBA, cela peut permettre une saisie intuitive dans une ListBox avec saisie dans TextBox.
    Merci de l'apport.

    ____________________________________________________________________


    Je profite de ce retour ici pour compléter, ou plutôt corriger mon message d'hier.
    Le comportement normal de la touche Echap est celui que j'ai baptisé Comportement 2.
    La touche Echap, utilisée dans une ComboBox, règle le ListIndex sur -1 et, donc, vide la zone de saisie.

    Le premier comportement observé est peut-être du à un comportement erratique de ma touche Echap.
    J'ai cru, dans la discussion relative à cette contribution, constater que Patrick et Pierre ont connu le même genre de désagrément et en ai tiré des conclusions trop hâtives.
    J'ai donc vérifié sur 4 pc, 2 en version Excel 2010 et 2 en 2007. Même résultat.

    Bonne journée

  6. #6
    Membre extrêmement actif
    Homme Profil pro
    Inscrit en
    Septembre 2013
    Messages
    1 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Septembre 2013
    Messages : 1 369
    Par défaut
    >Quid d'un contrôle ComboBox Multi colonnes...


    Boisgontier

Discussions similaires

  1. Saisie impossible si le texte ne correspond pas à la combobox.list
    Par Mr l'Ashanti dans le forum Macros et VBA Excel
    Réponses: 36
    Dernier message: 14/09/2018, 09h15
  2. rendre une saisie obligatoire dans un formulaire
    Par heteroclite dans le forum Général JavaScript
    Réponses: 9
    Dernier message: 17/09/2006, 23h26
  3. Comment rendre un internalFrame impossible à deplacer?
    Par akram_blouza dans le forum AWT/Swing
    Réponses: 1
    Dernier message: 17/03/2006, 18h07
  4. [PHP-JS] Comment rendre la saisie obligatoire ?
    Par whbh dans le forum Langage
    Réponses: 10
    Dernier message: 25/01/2006, 22h08
  5. Saisie impossible dans un TdbEdit
    Par deubal dans le forum Bases de données
    Réponses: 4
    Dernier message: 16/11/2005, 12h32

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo