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 :

Compteur de points sur UserForms successifs [XL-2016]


Sujet :

Macros et VBA Excel

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2018
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2018
    Messages : 5
    Points : 5
    Points
    5
    Par défaut Compteur de points sur UserForms successifs
    Bonjour !

    J'ai cree un quiz de cinq questions a l'aide de UserForms successifs, et j'aimerai que le score s'affiche dans un dernier UserForm a la fin du quiz. Pour cela j'ai declare une variable Integer ici appelee "points" qui est censee augmenter de 1 a chaque fois qu'une bonne reponse est validee. Le quiz fonctionne sans probleme, cependant, a la fin du quiz, la valeur de la variable reste a zero.

    Plus de details :

    - J'ai declare la variable dans un module standard : Global points As Integer


    - Le code de lancement du premier UserForm :

    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
    26
    27
    28
    29
    30
    31
    Sub activer_userform_q1()
    UserForm_question_1.Show
    End Sub
    
    - Le code standard de chaque UserForm :
    
    Private Static Sub CommandButton_next_1_Click()
    points = 0 'ligne presente seulement dans premier UserForm'
    If OptionButton1_q1 = True Then 'Reponse fausse'
    Unload UserForm_question_1 'Fermeture UserForm question 1'
    UserForm_question_2.Show 'Ouverture UserForm question 2'
    ElseIf OptionButton2_q1 = True Then 'Reponse fausse'
    Unload UserForm_question_1
    UserForm_question_2.Show
    ElseIf OptionButton3_q1 = True Then 'Reponse correcte'
    points = points + 1 'Ajout d'un point a la variable "points"'
    Unload UserForm_question_1
    UserForm_question_2.Show
    ElseIf OptionButton1_q1 = False And OptionButton2_q1 = False And OptionButton3_q1 = False Then
    MsgBox "Veuillez selectionner une reponse."
    End If
    End Sub
    
    - Et enfin le code de l'UserForm cense afficher le resultat :
    
    Private Sub UserForm_Initialize()
    Label1.Caption = points 'Affiche 0 peu importe le nombre de reponses correctes'
    End Sub
    
    
    
    Comment faire pour que la variable augmente effectivement a chaque bonne reponse et conserve la valeur actualisee tout au long du quiz ? Desole si c'est pas clair et merci d'avance pour vos reponses

  2. #2
    Responsable
    Office & Excel


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 122
    Points : 55 921
    Points
    55 921
    Billets dans le blog
    131
    Par défaut
    Salut.

    Je ne vois d'erreur manifeste dans le code, lu rapidement.

    As-tu déclaré également une variable points dans les userforms? Auquel cas, c'est cette variable qui est instanciée.
    Le code que tu donnes est-il bien celui que tu utilises?
    As-tu la ligne Option Explicit au début de chaque module pour te forcer à la déclaration de tes variables? L'erreur pourrait survenir à cause d'une faute de frappe dans le nom d'une variable et dans ce cas, Option Explicit la détecterait
    Es-tu certain d'avoir bien la ligne points = 0 uniquement au début du premier module?



    Cela étant, les variables globales, c'est à utiliser dans certains cas précis, mais certainement pas dans le tien.

    Perso, je ferais ceci. Je déclarerais une variable publique en début de chacun de mes userforms Public Points As Integer avant la première procédure ou fonction du userform.
    Je n'appellerais pas mes userforms en cascase(usf1 appelle usf2 appelle usf3, ...), mais successivement au sein d'une procédure qui les appelle et récupère entre chaque appel la valeur de la variable publique pour l'ajouter à une variable de procédure, comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Sub Test()
      Dim Points As Integer
      UserForm1.Show
      Points = Points + UserForm1.Points
      UserForm2.Show
      Points = Points + UserForm2.Points
     
    End Sub
    Au passage: Pour baliser le code, tu le sélectionnes puis tu cliques sur le bouton # de la barre d'édition du message, ce sera moins fastidieux que d'insérer les couleurs à la main
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2018
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2018
    Messages : 5
    Points : 5
    Points
    5
    Par défaut
    Hello,

    Je ne declarais qu'une fois la variable "points" avec la fonction Global dans un module a part mais je l'ai remplace par Public au debut de chaque procedure comme tu me l'a conseille.
    J'ai verifie le code, celui du message correspond bien a celui que j'utilise.
    Je n'ai pas la mention Option Explicit en haut de mes procedures.
    Et la ligne "points = 0" n'est presente qu'au debut du premier UserForm.

    Je vais essayer d'appeler les UserForms au sein d'une meme procedure mais comment ferais-tu pour par exemple pour declencher, au clic du bouton de commande, la fermeture de UserForm1 et l'ouverture de UserForm2 simultanee a partir d'une procedure externe ? J'ai essaye mais la fonction clic semble n'etre possible que dans la procedure de l'userform... Serait-il possible de laisser cette fonction dans l'userform et de l'appeler a partir de la procedure externe ?
    Et je ne comprend pas egalement a quoi renvoie "UserForm1.Points" et a quoi la variable "Points" correspondrait par rapport a la variable publique.

    Desole pour toutes les questions je ne comprend pas encore tres bien la logique VBA et merci d'avoir pris le temps de repondre

    Bonne fin d'apres-midi !

  4. #4
    Responsable
    Office & Excel


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 122
    Points : 55 921
    Points
    55 921
    Billets dans le blog
    131
    Par défaut
    En fait, il y a trois états d'un userform:
    1. non chargé
    2. chargé mais non visible
    3. visible



    Et ces trois états sont modifiés durant les étapes de la vie du userform dans le projet. En programmation trois couches (trois tiers), le userform fait partie de la couche appelée IHM (Interface Homme Machine ou encore PL pour Presentation Layer). Cette couche ne gère que les interactions entre le programme et l'utilisateur (pour faire simple). Elle ne réalise donc normalement aucun traitement métier (à part des vérifications de saisie, éventuellement) et encore moins des traitements de stockage ou de lecture de données sur un support de données (DB, feuille Excel, fichiers de divers types, ...)

    Au vu de ce qui précède, le userform sert uniquement à afficher de l'info à l'utilisateur et à en collecter en provenance de cet utilisateur. C'est pourquoi ce n'est pas à lui de compter les points récoltés dans tes différents userforms.

    Une procédure charge un userform, lui passe éventuellement des infos, l'ouvre, puis lorsque l'utilisateur ferme le userform, la procédure qui l'a ouvert reprend la main, collecte les infos dudit userform, le décharge puis appelle le suivant de la même manière. Dès lors, la procédure sur le click du bouton de fermeture du userform se résume en gros à le rendre invisible (ce qui rend la main à la procédure appelante).

    Eventuellement, si on n'a rien à faire entre le chargement et l'affichage, on peut directement utiliser la méthode .Show qui charge le formulaire s'il ne l'est pas.

    Normalement, le userform est dit encapsulé, c'est-à dire qu'il ne doit normalement pas avoir besoin de ressources extérieures (en termes de variables, notamment, et donc, pas de variables globales). En quelque sorte, il est autonome. En fait, il doit être écrit de manière à pouvoir être réutilisé dans un autre contexte dans lequel il doit jouer le même rôle sans dépendre de code externe (et notamment de variables globales).

    On va imaginer un scénario complet pour que tu vois le principe de fonctionnement. On doit ouvrir un userform1, lui passer un message qui doit être affiché sur la barre de titre, l'afficher, puis récupérer les infos saisies, puis le fermer et passer à la suite du traitement.

    Dans l'exemple qui suit, on dispose de deux userforms identiques: textbox tboAnswer et deux boutons de commande btnValidate et btnCancel. Le code des userforms est le suivant:
    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
    26
    27
    28
    29
    30
    Option Explicit
     
    Public Choice As String
    Public Points As Integer
     
    Private Sub btnCancel_Click()
      Choice = "Cancel"
      Me.Hide
    End Sub
     
    Private Sub btnValidate_Click()
      If AnswerIsOk Then
        TransferValues
        Choice = "Validate"
        Me.Hide
      Else
        MsgBox "Veuillez corriger votre saisie svp", vbExclamation
      End If
    End Sub
     
    Function AnswerIsOk() As Boolean
    '  ...
    '  ...
    '  ...
      AnswerIsOk = True
    End Function
     
    Sub TransferValues()
      Points = txtAnswer.Value * 1
    End Sub
    On voit donc le rôle réduit de btnValidate. Il appelle la procédure de vérification, si c'est ok, il appelle la procédure de transfert des données (on pourrait jouer autrement pour cela, il y a des variantes possibles), puis masque le userform, ce qui rend la main à la procédure qui appelle le userform. On voit donc qu'il ne fait aucun traitement: il ne vérifie pas, il ne transfère pas. Il appelle les procédures ad hoc dont c'est la responsabilité.

    On remarque au passage que ce bouton attribue la valeur "Validate" à la variable publique Choice et que la variable Points du userform reçoit la valeur saisie dans le textbox si correcte (selon la fonction, fictive dans ce cas-ci, de vérification). Le second userform a, dans ton cas, un fonctionnement identique.

    Au départ, le Userform1 est déchargé (Etat 1). La procédure appelante charge d'abord le userform1 sans l'afficher (état 2), ce qui permet de lui passer le texte à afficher sur la barre du userform, puis on l'affiche (Etat 3). Après un clic sur Validate ou Cancel, la main est rendue à la procédure appelante grâce à Me.Hide. Le userform repasse à l'état 2, il est donc toujours chargé et on peut en récupérer des valeurs, puis on le décharge (Etat 1) et on passe à la suite.
    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
    26
    Option Explicit
     
    Sub Play()
      Dim Points As Integer
      Dim Choice As String
     
      Load UserForm1
      UserForm1.Caption = "Bonjour" + Application.UserName
      UserForm1.Show
      Choice = UserForm1.Choice
      If Choice = "Validate" Then
        Points = UserForm1.Points
      End If
      Unload UserForm1
     
      If Choice = "Validate" Then
        Load UserForm2
        UserForm2.Caption = "Bonjour" + Application.UserName
        UserForm2.Show
        Choice = UserForm2.Choice
        If Choice = "Validate" Then
          Points = Points + UserForm2.Points
        End If
        Unload UserForm2
      End If
    End Sub
    Ca paraît évidemment plus lourd que ton code actuel, mais c'est le fonctionnement normal d'un userform si tu souhaites coder proprement et faciliter la maintenance de ton code. Ca fait quelques lignes supplémentaires mais la qualité d'un code ne se mesure pas au nombre de lignes produites.

    En codant tous mes userforms sur le même moule, d'abord ça va vite car cela devient une habitude, puis je m'y retrouve beaucoup plus facilement lorsque je dois m'y replonger.


    Option Explicit
    Au passage, tu dis que tu n'as pas Option Explicit au début de tes modules. Je ne peux que t'encourager à ce que cette ligne soit présente. Elle t'obligera à déclarer sytématiquement tes variables avant de les utiliser, ce qui évitera bien des erreurs (comme probablement celle que tu as rencontrée).

    Pour la placer automatiquement sur tes nouveaux modules, va dans Outils\Options\Editeur et coche Déclaration des variables obligatoire (au passage, décoche si ce n'est déjà fait Vérification automatique de la syntaxe, la ligne en erreur de syntaxe sera bien marquée en rouge mais au moins tu n'auras pas ce message intempestif en plein milieu de l'écran, brise-biscuits lorsque tu réalises des copier-coller de parties de code).

    La case Déclaration... cochée imposera à ton éditeur de placer Option Explicit au début de chaque nouveau module. Pour les modules existants, à toi de choisir si tu la mets à la main ou pas (perso, je conseille de le faire, mais cela risque de t'amener à devoir modifier pas mal de code pour déclarer tes variables.)
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2018
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2018
    Messages : 5
    Points : 5
    Points
    5
    Par défaut
    Ca fait beaucoup d'infos mais je commence a mieux comprendre Je vais bachoter tout ca et essayer de reecrire mon code en me basant sur ton modele

    Merci beaucoup pour ta reponse et bonne journee !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [XL-2003] UserForm : Alimenter une base de données en continu - Petit point sur macro à résoudre
    Par BtjpsspgrW dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 11/09/2014, 08h12
  2. identifier un point sur l'ecran
    Par alionel dans le forum MFC
    Réponses: 2
    Dernier message: 25/02/2005, 16h12
  3. calcul d'un point sur la base d'un cone
    Par Admin dans le forum Algorithmes et structures de données
    Réponses: 4
    Dernier message: 18/11/2003, 21h18

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