VBA - Dialogues et formulaires

Auteur: Michel Berthiaume
Reproduction interdite sans autorisation

Sur cette page

Dialogues, formulaires et alternatives

L'éditeur

Les contrôles

Ouvrir et fermer un formulaire

Exemple 1: Écran d'accueil

Exemple 2: Sélectionner un dossier

Exemple 3: Barre de progression

Exemple 4: Saisir et valider des données

Objets et événements Excel

Conseils de programmation

Liste d'instructions

Dialogues, formulaires et alternatives

Les programmes utilisent les dialogues et les formulaires pour obtenir des données ou des instructions de l'utilisateur, pendant l'exécution du programme.

Certains formulaires offrent des menus, permettant à l'utilisateur de choisir entre différentes actions possibles.
En VBA Excel, vous pouvez utiliser une feuille Excel (de préférence la première) à la place de formulaires VBA pour construire des menus.
Cela se fait simplement en insérant des objets (boutons de formulaire par exemple) sur la feuille Excel et en y assignant une macro VBA ou un hyperlien.

Par ailleurs, il se peut que votre programme VBA doive obtenir des instructions ou des données de l'utilisateur.

Si les choix sont simples (continuer ou arrêter, par exemple), il est recommandé d'utiliser la fonction:

MsgBox(message[, boutons] [, titre])

Où:

  • message est le message affiché par la fonction. On peut utiliser la constante VBA vbCrLf pour insérer des changements de lignes dans un message long.

  • boutons Expression numérique indiquant les boutons disponibles dans la boîte de dialogue. Par défaut, il n'y a que le bouton Ok.
    Valeurs possibles:
    0 (vbOKOnly) Affiche le bouton OK uniquement.
    1 (vbOKCancel) Affiche les boutons OK et Annuler.
    2 (vbAbortRetryIgnore) Affiche les boutons Abandonner, Réessayer et Ignorer.
    3 (vbYesNoCancel) Affiche les boutons Oui, Non et Annuler.
    4 (vbYesNo) Affiche les boutons Oui et Non.
    5 (vbRetryCancel) Affiche les boutons Réessayer et Annuler.
    16 (vbCritical) Affiche l'icône Message critique.
    32 (vbQuestion) Affiche l'icône Requête d'avertissement.
    48 (vbExclamation) Affiche l'icône Message d'avertissement.
    64 (vbInformation) Affiche l'icône Message d'information.
    256 (vbDefaultButton2) Le deuxième bouton est le bouton par défaut.
    512 (vbDefaultButton3) Le troisième bouton est le bouton par défaut.
    768 (vbDefaultButton4) Le quatrième bouton est le bouton par défaut.
    524288 (vbMsgBoxRight) Le teste est aligné à droite.
    (certaines valeur exotiques sont omises)

    Le premier groupe de valeurs (0 à 5) décrit le nombre et le type de boutons affichés dans la boîte de dialogue. Le deuxième groupe (16, 32, 48 et 64) décrit le style d'icône. Le troisième groupe (256 et 512) définit le bouton par défaut. Au moment d'additionner ces nombres pour obtenir la valeur finale de l'argument buttons, ne sélectionnez qu'un seul nombre dans chaque groupe.
    Les constantes entre parenthèses peuvent être utilisées à la place des valeurs correspondantes et sont plus explicites.

  • titre titre affiché en haut de la boîte de dialogue.

La fonction MsgBox() retourne une valeur différente selon le bouton cliqué pour fermer la boîte de dialogue:

  • 1 (vbOK) OK

  • 2 (vbCancel) Annuler

  • 3 (vbAbort) Abandonner

  • 4 (vbRetry) Réessayer

  • 5 (vbIgnore) Ignorer

  • 6 (vbYes) Oui

  • 7 (vbNo) Non

La boîte de dialogue ouverte par l'instruction MsgBox() est toujours modale, c'est à dire que l'exécution du programme VBA est interrompu et que le classeur Excel n'est pas accessible tante que la boîte de dialogue ne sera pas fermée par l'utilisateur.

MsgBox() permet au programme d'offrir jusqu'à 3 choix (3 boutons) à l'utilisateur.

 

Si la boîte de dialogue doit permettre à l'utilisateur de fournir une valeur (et une seule), il est possible d'utiliser l'instruction:

InputBox(message[, titre] [, défaut])

Où:

  • message est le message affiché par la fonction. On peut utiliser la constante VBA vbCrLf pour insérer des changements de lignes dans un message long.

  • titre titre affiché en haut de la boîte de dialogue.

  • defaut valeur qui sera utilisée si l'utilisateur clique sur Ok sans fournir de valeur.

La boîte de dialogue ouverte par l'instruction InputBox() est toujours modale, c'est à dire que l'exécution du programme VBA est interrompu et que le classeur Excel n'est pas accessible tante que la boîte de dialogue ne sera pas fermée par l'utilisateur.

InputBox() offre à l'utilisateur une zone de texte et 2 boutons: Ok et Annuler.

 

Si Excel dispose d'une boîte de dialogue qui convient au besoin, il est possible de les utiliser à partir d'un programme VBA:

Collection Dialogs
d'objets Dialog

Chaque objet Dialog correspond à une boîte de dialogue Excel.
La méthode Show affiche la boîte de dialogue et retourne la réponse fournie par l'utilisateur.
On peut utiliser une constante VBA pour identifier la boîte de dialogue voulue:

Dialogs(xlDialogOpen).Show Ouvrir fichier
Dialogs(xlDialogSaveAs).Show Enregistrer sous
Il y a plus de 250 autres boîtes de dialogues disponibles dans Excel. Voir l'aide VBA, ou utiliser l'enregistreuse de macro-commande pour identifier le nom de la boîte de dialogue que vous voulez utiliser.

 

Il y a aussi l'objet FileDialog:

Objet FileDialog

Cet objet permet d'utiliser les boîte de dialogues de fichier standard Ouvrir et Enregistrer de Microsoft Office.

Utilisez la propriété DialogType pour spécifier quelle boîte de dialogue ouvrir:

msoFileDialogFilePicker Choisir un ou plusieurs fichiers, dont les chemins d'accès sont dans la collection FileDialogSelectedItems
msoFileDialogFolderPicker Choisir un dossier,  dont le chemins d'accès est dans la collection FileDialogSelectedItems
msoFileDialogOpen Choisir un ou plusieurs fichiers qui peuvent être ouverts avec la méthode Execute
msoFileDialogSaveAs Choisir un nom de fichier et un chemin d'accès, et d'enregistrer le classeur Excel sous ce nom avec la méthode Execute
Plusieurs autres propriétés de cet objet permettent de spécifier le titre, des valeurs par défaut, des filtres, etc.

L'objet FileDialog a 2 méthodes:

  • Show qui affiche la boîte de dialogue spécifiée par la propriété DialgType
  • Execute qui exécute l'action appropriée pour les dialogues de type msoFileDialogOpen et msoFileDialogSaveAs

Pour les besoins plus complexes, comme la saisie de plusieurs valeurs avec une validation importante, vous pouvez utiliser un formulaire VBA.

Finalement, pour une saisie vraiment efficace de données vous devriez utiliser Access, dont les formulaires sont beaucoup plus puissants que ceux que vous pouvez programmer en VBA Excel.

L'éditeur de formulaires VBA (MS Forms)

L'éditeur VBA comporte une fenêtre spécifique pour créer ou modifier un formulaire.

Créez un formulaire:

Du menu Insertion, sélectionnez UserForm
L'explorateur de projet ouvre une branche Feuilles qui ne contient pas des feuilles Excel, mais des formulaires VBA.
La fenêtre principale affiche le cadre d'un formulaire.
C'est l'entête de l'explorateur de projet qui contrôle l'affichage de la fenêtre principale:

Affichage du code VBA associé au formulaire (une sorte de module incorporé)
Alternatives: Menu Affichage/Code ou F7

Affichage du formulaire
Alternatives: Menu Affichage/Objet ou Maj+F7

Modifie le mode d'affichage de l'explorateur de projets. Inutile.

 

La boîte à outils devrait aussi apparaître.

Sinon, du menu Affichage, sélectionnez :

Finalement, remarquez sous l'explorateur de projet, la feuille de propriétés du formulaire. C'est là que seront affichées les propriétés de l'objet sélectionné dans le formulaire (ou celles du formulaire lui-même)

 

Empressez-vous de changer le nom du formulaire que VBA a nommé UserForm1 (ou n).

Il est important de choisir le nom définitif du formulaire AVANT de commencer à lui ajouter du code VBA.

Événements

On attache des procédures sub aux événements que subit le formulaire.

Par exemple, une procédure sub nommée
Sub UserForm_Initialize()
est exécutée à chaque fois que le formulaire est ouvert (initialisé).

Pour écrire une procédure événementielle, afficher la fenêtre code du formulaire (F7), sélectionner l'objet qui subit l'événement (le formulaire ou un contrôle du formulaire), dans la liste déroulante de gauche, et l'événement voulu dans la liste de droite. L'éditeur VBA crée alors une procédure Sub vide correspondant à l'événement.


Il est aussi possible de créer une procédure Sub événementielle d'un contrôle en double-cliquant dessus.
C'est alors l'événement par défaut du contrôle qui est choisi.

Contrôles disponibles

On appelle contrôle les classes d'objet qu'on peut insérer dans un formulaire. La description détaillée de chacun
de ceux qui sont disponibles en VBA dépasse le cadre du présent texte, mais voici une présentation sommaire de chacun d'entre eux:

outil de sélection n'est pas un contrôle, mais l'outil à utiliser pour sélectionner un ou plusieurs contrôles.

 

 
libellé (intitulé ou label) sert à ajouter du texte explicatif dans le formulaire, comme des instructions à l'utilisateur ou des étiquettes pour les zones de texte.

 

Propriétés intéressantes:
  • Caption
  • Value
  • TextAlign

 


 

zone de texte (textbox) sert à inclure dans le formulaire une zone dans laquelle l'utilisateur sera invité à entrer des valeurs. La valeur entrée est TOUJOURS enregistrées en format texte, et le programme VBA devra identifier et faire les conversions appropriées.

 

Propriétés intéressantes:
  • Name
  • Enabled
  • Value
  • Text
  • ControlSource
  • TabIndex
  • TextAlign

Événements intéressants:

  • Change
  • Enter
  • Exit
  • BeforeUpdate
  • AfterUpdate
Zone de liste modifiable (déroulante ou ComboBox) Sert à inclure dans le formulaire une zone de texte offrant aussi une liste de choix possibles. Propriétés intéressantes:
  • Name
  • Enabled
  • Visible
  • Value
  • TabIndex
  • Text
  • TextAlign
  • BoundColumn
  • ColumnCount
  • ControlSource
  • RowSource

Événements intéressants:

  • Change
  • Enter
  • Exit
  • BeforeUpdate
  • AfterUpdate

 

Zone de liste (ListBox) Sert à inclure dans le formulaire une zone de liste de choix possibles. Propriétés intéressantes:
  • Name
  • Enabled
  • Visible
  • Value
  • TabIndex
  • Text
  • TextAlign
  • BoundColumn
  • ColumnCount
  • ControlSource
  • RowSource

Événements intéressants:

  • Change
  • Enter
  • Exit
  • BeforeUpdate
  • AfterUpdate

 

Case à cocher (CheckBox) Sert à inclure dans le formulaire une (souvent plusieurs) case(s) à cocher Propriétés intéressantes:
  • Name
  • Caption
  • Enabled
  • Visible
  • Value
  • TabIndex
  • TextAlign
  • ControlSource

Événements intéressants:

  • Change
  • Enter
  • Exit
  • BeforeUpdate
  • AfterUpdate
Bouton d'option (OptionButton) Sert à inclure dans le formulaire un (souvent plusieurs) boutons d'option Propriétés intéressantes:
  • Name
  • Caption
  • Enabled
  • Visible
  • Value
  • TextAlign
  • ControlSource

Événements intéressants:

  • Change
  • Enter
  • Exit
  • BeforeUpdate
  • AfterUpdate
Bouton Bascule (ToggleButton) Désuet: utiliser une case à cocher
Cadre (Frame) Sert à regrouper plusieurs contrôles d'un formulaire Propriétés intéressantes:
  • Name
  • Caption
  • Enabled
  • Visible

Événements intéressants:

  • Enter
  • Exit
Bouton de commande (CommandButton) Sert à inclure dans le formulaire un (souvent plusieurs) bouton(s) Propriétés intéressantes:
  • Name
  • Caption
  • Default
  • Enabled
  • TabIndex
  • Visible

Événements intéressants:

  • Click
Contrôle d'onglet (TabStrip) Sert à inclure des onglets dans le formulaire Propriétés intéressantes:
  • Name
  • Enabled
  • Value

Événements intéressants:

  • Change
Multi Page (Page) Sert à inclure des pages dans le formulaire Propriétés intéressantes:
  • Name
  • Enabled
  • Value

Événements intéressants:

  • Change
Barre de défilement (ScrollBar) Sert à inclure une barre de défilement dans le formulaire. Propriétés intéressantes:
  • Name
  • Enabled
  • Min
  • Max
  • Value
  • ControlSource
  • Orientation

Événements intéressants:

  • Change
  • Enter
  • Exit
  • BeforeUpdate
  • AfterUpdate
Toupie (SpinButton) Sert à inclure des flèches de défilement Propriétés intéressantes:
  • Name
  • Enabled
  • Min
  • Max
  • Value
  • ControlSource
  • Orientation

Événements intéressants:

  • Change
  • Enter
  • Exit
  • BeforeUpdate
  • AfterUpdate
Image Sert à inclure une image dans le formulaire Propriétés intéressantes:
  • Name
  • Enabled
  • Picture

Événements intéressants:

  • Click
RefEdit Sert à inclure une zone de sélection de plage Excel dans le formulaire

Remarque : si il y n'a aucun bouton RefEdit dans la boîte à outils, procédez comme suit :
Dans le menu Outils , cliquez sur Autres contrôles .
Dans la boîte de dialogue Contrôles supplémentaires , activez la case à cocher RefEdit.ctrl et puis cliquez sur OK.

Propriétés intéressantes:
  • Name
  • Enabled
  • Value
  • Text

Événements intéressants:

  • Change
  • Enter
  • Exit
  • BeforeDragOver
  • BeforeUpdate
  • AfterUpdate
 

Ouvrir et fermer un formulaire

Pour ouvrir un formulaire, il n'y a pas d'instruction VBA. On utiliser plutôt la méthode Show (voir exemples).

Pour réafficher un formulaire déjà ouvert, parce qu'un contrôle a pu changer, ou utilise la méthode RePaint.

Pour fermer un formulaire, on peut utiliser la méthode Close (ou même Hide), mais celle-ci ne libère pas l'espace mémoire occupée par le formulaire.

On utilise plus souvent l'instruction VBA:

Unload objet

Où:

  • objet est le nom du formulaire à supprimer.

 

Lorsque l'instruction est utilisée dans le module VBA appartenant au formulaire, on préfère  utiliser:
Unload Me
L'objet Me étant le formulaire en cours.

Exemples

Il est fortement déconseillé d'utiliser quelque forme de dialogue que ce soit dans une fonction (Function) VBA.
Une fonction ne devrait communiquer avec l'environnement et l'utilisateur que par ses paramètres (en entrée) et sa valeur (en sortie).

Les exemples ci-dessous ne sont donc que des procédures Sub.

Exemple 1: Écran d'accueil

Technique 1: utilisant une feuille Excel

Cet exemple requiert:

Option Explicit
Private Sub Workbook_Open()
'Auteur Michel Berthiaume
'Afficher une feuille Excel de présentation de l'application

Dim dtDate As Date

    If Sheets("Accueil").Range("B1").Value = False Then 'Si l'utilisateur n'a pas coché
        Sheets("Accueil").Visible = True
        Sheets("Accueil").Select
        dtDate = Now()
        Do Until Now() - dtDate > (1 / 24 / 60 / 60 * 3) 'Boucle d'attente de 3 secondes
            DoEvents 'Permet à l'utilisateur de cocher la case
        Loop
    End If
    Sheets("Accueil").Visible = False
End Sub

 

Technique 2: utilisant un formulaire

Cet exemple requiert:

Option Explicit
Private Sub Workbook_Open()
'Auteur Michel Berthiaume
'Afficher un formulaire VBA Excel (Microsoft Forms) de présentation de l'application

    frmDocumentation.show

End Sub

Option Explicit
Private Sub UserForm_Activate()
'Auteur: Michel Berthiaume
'Accueil dans un classeur Excel

Dim dtDate As Date

    If Me.cbMessage.Value = False Then 'Seulement si la case n'est pas cochée
        Me.Repaint 'Afficher le formulaire
        dtDate = Now()
        Do Until (Now() - dtDate) > (1 / 24 / 60 / 60 * 3) 'Boucle d'attente de 3 secondes
            DoEvents 'Permet à l'utilisateur de cocher la case
        Loop
    End If
    Unload Me 'Effacer le formulaire

End Sub

Exemple 2: Sélectionner un dossier

L'exemple ci-dessous crée une liste de fichiers d'un dossier choisi par l'utilisateur.

Il requiert une feuille Excel contenant des plages nommées:

Sub ListeFichiers()
'Auteur: Michel Berthiaume
'Créer une feuille Excel contenant la liste des fichiers d'un dossier choisi par l'utilisateur
Dim FSO As New Scripting.FileSystemObject 'Requiert une référence à Microsoft Scripting Runtime
Dim fsFichier As File
Dim lLigne As Long

    'Obtenir le nom du dossier
    With Application.FileDialog(msoFileDialogFolderPicker)
        .show 'Afficher la boîte de dialogue
        If .SelectedItems.Count <> 1 Then 'Opération annulée
            Range("NomDossier").Value = ""
            Exit Sub
         End If
        Range("NomDossier").Value = .SelectedItems(1) 'Inscrire dans la feuille
    End With

    'Inscrire les fichiers
    With Range("ListeFichiers")
        'Effacer les données présentes
        .Range(Cells(2, 1), Cells(.CurrentRegion.Rows.Count- 1, _
            .CurrentRegion.Rows.Count)).Clear

        lLigne = 1 'Offset initial
        For Each fsFichier In FSO.GetFolder(Range("NomDossier").Value).Files
            .Offset(lLigne, 0).Value = fsFichier.Name
            .Offset(lLigne, 1).Value = fsFichier.Size
            .Offset(lLigne, 2).Value = fsFichier.DateLastModified
            lLigne = lLigne + 1
        Next
    End With

End Sub

Commentaires:

Exemple 3: Barre de progression

L'exemple précédent peut être long à exécuter, si le dossier choisi contient beaucoup de fichiers.
Ajoutons une barre de progression.

Technique 1: En utilisant la ligne d'état

Excel permet d'afficher un message dans la ligne d'état en bas le l'écran, en utilisant la propriété StatusBar.

Un programme peut appeler la procédure suivante pour afficher un % de progression. Il suffit qu'il rappelle la procédure à chaque fois que le % est modifié.

Sub AfficheProgression(PourcentageEffectué)
'Affiche un pourcentage et une barre de progression dans la barre d'état Excel
'PourcentageEffectué doit être entre 0 et 1 (inclus)
'Si 0, négatif ou >1, efface barre d'état
'Par Michel Berthiaume
'Inspiré du programme de Dick Kusleika

    If PourcentageEffectué > 0 And PourcentageEffectué <= 1 Then
        Application.StatusBar = Format(PourcentageEffectué, "0%") & " " & String(PourcentageEffectué * 50, Chr(31))
    Else
        Application.StatusBar = False
    End If
End Sub

Commentaires:

On modifie donc le programme de l'exemple précédent ainsi:

Sub ListeFichiers()
'Auteur: Michel Berthiaume
'Créer une feuille Excel contenant la liste des fichiers d'un dossier choisi par l'utilisateur
DimFSO As New Scripting.FileSystemObject 'Requiert une référence à Microsoft Scripting Runtime
Dim fsFichier As File
Dim lLigne As Long
Dim lNombre As Long 'Nombre de fichiers



    'Obtenir le nom du dossier
    With Application.FileDialog(msoFileDialogFolderPicker)
        .show 'Afficher la boîte de dialogue
        If .SelectedItems.Count <> 1 Then 'Opération annulée
            Range("NomDossier").Value = ""
            Exit Sub
         End If
        Range("NomDossier").Value = .SelectedItems(1) 'Inscrire dans la feuille
    End With


    lNombre = FSO.GetFolder(Range("NomDossier").Value).Files.Count

    'Inscrire les fichiers
    With Range("ListeFichiers")
        'Effacer les données présentes
        .Range(Cells(2, 1), Cells(.CurrentRegion.Rows.Count- 1, _
            .CurrentRegion.Rows.Count)).Clear

        lLigne = 1 'Offset initial
        For Each fsFichier In FSO.GetFolder(Range("NomDossier").Value).Files
            Call AfficheProgression(lLigne / lNombre) 'Afficher progression
            .Offset(lLigne, 0).Value = fsFichier.Name
            .Offset(lLigne, 1).Value = fsFichier.Size
            .Offset(lLigne, 2).Value = fsFichier.DateLastModified
            lLigne = lLigne + 1
        Next
    End With
 

    Call AfficheProgression(0) 'Effacer la barre de progression
End Sub

Sub AfficheProgression(PourcentageEffectué)
'Affiche un pourcentage et une barre de progression dans la barre d'état Excel
'PourcentageEffectué doit être entre 0 et 1 (inclus)
'Si 0, négatif ou >1, efface barre d'état
'Par Michel Berthiaume
'Inspiré du programme de Dick Kusleika

    If PourcentageEffectué > 0 And PourcentageEffectué <= 1 Then
        Application.StatusBar = Format(PourcentageEffectué, "0%") & " " & String(PourcentageEffectué * 50, Chr(31))
    Else
        Application.StatusBar = False
    End If

End Sub

Technique 2: En utilisant un formulaire

Cet technique requiert:

Il faut associer au formulaire (et à ses contrôles) le code VBA suivant:

Option Explicit
'Auteur: Michel Berthiaume
'Inspiré du travail de John Walkenbach
'Formulaire de production de liste de fichiers

Private Sub UserForm_Initialize()
'Initialiser le formulaire
    If tDossier.Value = "" Then
        tDossier.Value = ActiveWorkbook.Path 'Dossier par défaut
    End If
End Sub

Private Sub bChoisirDossier_Click()
'Obtenir le nom du dossier
    With Application.FileDialog(msoFileDialogFolderPicker)
        .Show 'Afficher la boîte de dialogue
        If .SelectedItems.Count <> 1 Then 'Opération annulée
            Range("NomDossier").Value = ""
            Exit Sub
        End If
        tDossier.Value = .SelectedItems(1) 'Inscrire dans le formulaire et la feuille
    End With
End Sub

Private Sub bGo_Click()
'Produire la liste des fichiers
'Inscrire les fichiers
Dim FSO As New Scripting.FileSystemObject 'Requiert une référence à Microsoft Scripting Runtime
Dim fsFichier As File
Dim lLigne As Long
Dim lNombre As Long 'Nombre de fichiers



    On Error GoTo DossierInexistant
    lNombre = FSO.GetFolder(Range("NomDossier").Value).Files.Count
    On Error GoTo 0
    If lNombre = 0 Then
        Exit Sub
    End If

With Range("ListeFichiers")
    'Effacer les données présentes
    .Range(Cells(2, 1), Cells(.CurrentRegion.Rows.Count - 1, _
        .CurrentRegion.Columns.Count)).Clear

    lLigne = 1 'Offset initial
    For Each fsFichier In FSO.GetFolder(Range("NomDossier").Value).Files
        Call AfficheProgression(lLigne / lNombre) 'Afficher progression
        .Offset(lLigne, 0).Value = fsFichier.Name
        .Offset(lLigne, 1).Value = fsFichier.Size
        .Offset(lLigne, 2).Value = fsFichier.DateLastModified
        lLigne = lLigne + 1
    Next
End With
End Sub

DossierInexistant:
    MsgBox "Dossier inexistant", , "Liste de fichiers d'un dossier"
End Sub

Private Sub bQuitter_Click()
    Unload Me
End Sub

Sub AfficheProgression(PourcentageEffectue)
    FrameProgress.Caption = Format(PourcentageEffectue, "0%")
    LabelProgress.Width = PourcentageEffectue * (FrameProgress.Width - 10)
    Me.Repaint
End Sub
 

 

Finalement, ajouter la procédure:

Sub OuvrirfrmListeFichiers()
    FrmListeFichiers.Show
End Sub

dans un module.

Lorsque exécutée, cette dernière procédure exécutera le formulaire.

Exemple 4: Saisir et valider des données

Voyons comment on peut utiliser Excel pour saisir les informations nécessaires à une facturation de vente.

Technique 1: utilisant une feuille Excel

Créez la feuille Excel suivante:

Ayant les caractéristiques suivantes:

Chacun des trois boutons est associé au procédures correspondantes:

Sub Initial()
'Auteur: Michel Berthiaume
'Initialiser ou réinitialiser la feuille facture
'l'action est déterminée par le contenu du bouton: Démarrer la saisie ou Terminer la saisie
'Configuré pour Excel 2007
Dim sBouton As Shape

    'Trouver le bouton
    For Each sBouton In ActiveSheet.Shapes 'Examiner chaque bouton

        If sBouton.AlternativeText = "Démarrer la saisie" Then

            'Initialiser
            With ActiveWindow 'Déactive certains affichages
                .DisplayHeadings = False
                .DisplayHorizontalScrollBar = False
                .DisplayVerticalScrollBar = False
                .DisplayWorkbookTabs = False
            End With
            With Application
                .DisplayFormulaBar = False
                .DisplayStatusBar = False
            End With
   
            'Modifier le bouton
            Worksheets("Facture").Unprotect
            sBouton.AlternativeText = "Terminer la saisie"
            sBouton.Select                           'Impossible de modifier l'étiquette directement
            Selection.Characters.Text = "Terminer la saisie"
            Range("B3").Select
            Worksheets("Facture").Protect
            Exit For 'Pas besoin de regarder les autres boutons

        ElseIf sBouton.AlternativeText = "Terminer la saisie" Then
   
            'Rétablir l'affichage
            With ActiveWindow
                .DisplayHeadings = True
                .DisplayHorizontalScrollBar = True
                .DisplayVerticalScrollBar = True
                .DisplayWorkbookTabs = True
            End With
            With Application
                .DisplayFormulaBar = True
                .DisplayStatusBar = True
            End With
            'Modifier le bouton
            Worksheets("Facture").Unprotect
            sBouton.AlternativeText = "Démarrer la saisie"
            sBouton.Select                         'Impossible de modifier l'étiquette directement
            Selection.Characters.Text = "Démarrer la saisie"
            Range("B3").Select
            Worksheets("Facture").Protect
            Exit For 'Pas besoin de regarder les autres boutons
        End If
    Next
End Sub

Sub Nouvelle()
'Auteur: Michel Berthiaume
'Prépare la feuille pour une nouvelle facture

    Range("B3:D5").ClearContents
    Range("B7:D16").ClearContents
    Worksheets("Facture").Unprotect
    Range("Référence") = Range("Référence") + 1
    Worksheets("Facture").Protect
    Range("B3").Select
End Sub

Sub Enregistrer()
'Auteur: Michel Berthiaume
'Exécuté par bouton Ok de boîte de dialogue

    With Application.FileDialog(msoFileDialogSaveAs)
        .InitialFileName = "Facture de " & Range("NomClient").Value & " du " & Format(Date, "Long Date") & ".xls"
        .Show 'Afficher la boîte de dialogue
        If .SelectedItems.Count <> 1 Then 'Opération annulée
            Exit Sub
        End If
        ActiveWorkbook.SaveAs Filename:=.SelectedItems(1)
    End With

End Sub
 

Technique 2: utilisant un formulaire

Ici, les factures seront enregistrées dans une liste Excel.
Chaque facture est identifiée par un numéro de référence (séquentiel).
Chaque facture est décrite sur plusieurs lignes:

Cette liste de factures est facilement utilisable avec les filtres, le tris et le tableau croisé dynamique d'Excel.

Créez la feuille Excel selon le modèle ci dessous:

La partie gauche contiendra la liste de facture.

Au milieu (colonne K), le bouton qui appelle le formulaire.

À droite, les colonnes L, M et N contiennent des valeurs qui seront utilisées par le formulaire.

Pour que le bouton Saisir factures ouvre le formulaire:

Le formulaire frmFacture est conçu de la façon suivante:

Le formulaire compte les zones de texte suivantes:

Nom Propriétés importantes Description
tClient TabIndex: 0 Contiendra le nom du client
tAdresse1 TabIndex: 1 Ligne 1 de l'adresse du client
tAdresse2 TabIndex: 2 Ligne 2 de l'adresse du client
tLigne Enabled: False Numéro de la ligne dans la facture
tItem TabIndex: 4 Description de l'item acheté
tNombre TabIndex: 5 Nombre d'items achetés
tPrix TabIndex: 6 Prix unitaire
tMontant Enabled: False Extension (Nombre * Prix)

Notez que les zones tLignes et tMontant, qui sont gérées par le programme, sont désactivées (Enabled: False).

Chacune de ces zones de texte est accompagnée d'une étiquette (Lablel) qui la décrit.

Il y a aussi les 8 étiquettes qui décrivent les montants de la facture. 4 d'entre elles sont descriptives et ont les noms assignés lors de leur création (Label15, Label16, etc.).
Les 4 autres seront utilisées par le programme pour afficher les valeurs et se nomment: lSousTotal, lTPS, lTVQ et lTotal.

Deux autres étiquettes, tRéférence et tDate afficheront le numéro de la facture affichée et sa date.

Finalement, le formulaire compte 5 boutons:

Nom Propriétés importantes Description
bLignePréc TabIndex: 8
Enabled: False
Picture: Image d'un triangle
Enregistre la ligne affichée.
Permet de reculer d'une ligne dans la facture.
bLigneSuiv TabIndex: 9
Enabled: False
Picture: Image d'un triangle
Enregistre la ligne affichée.
Permet de passer à la ligne suivante dans la facture
bEnregistrer TabIndex: 10
Caption: Enregistrer
Enabled: False
Enregistre la facture.
bAnnuler TabIndex: 11
Caption: Annuler facture
Enabled: False
Annule la facture (et les lignes enregistrées)
bQuitter TabIndex: 12
Caption: Quitter
Enabled: True
Ferme le formulaire

Le code VBA associé à ce formulaire peut être groupé en quelques blocs:

D'abord la documentation:

Option Explicit
'Auteur: Michel Berthiaume
'Formulaire d'enregistrement de factures
'Noter que le programme n'utilise aucune variable globale.
'Les données externes aux procédures sont stockées
'Soit dans le formulaire, soit dans la feuille Excel
'Ce qui les rend plus accessibles.
'
'Données critiques:
'Range("ProchaineRéférence"): numéro de la prochaine facture
'Range("RéférenceÉditée"): numéro de la facture en cours (synchrone avec la suivante)
'frmFacture.tRéférence: numéro de la facture en cours (synchrone avec la précédente)
'Range("LigneÉditée"): numéro de la ligne en cours de la feuille Excel
'frmFacture.tLigne: numéro de ligne en cours de la facture en cours

L'initialisation:

Private Sub UserForm_Initialize()
'Initialiser le formulaire
    tDate = Date
    Range("RéférenceÉditée").Value = Range("ProchaineRéférence").Value
    tLigne.Value = 1 'Ligne 1 de nouvelle facture
    Range("LigneÉditée").Value = Range("A1").CurrentRegion.Rows.Count + 1 'Première ligne vide
    Call AfficherTot
End Sub

Commentaires:

Le traitement des lignes de facture:

Private Sub tNombre_Change()
    'Recalculer montant
    tMontant.Value = Val(tNombre.Value) * Val(tPrix.Value)
End Sub

Private Sub tPrix_Change()
    'Recalculer montant
    tMontant.Value = Val(tNombre.Value) * Val(tPrix.Value)
End Sub

Private Sub tMontant_Change()
    'Activer les boutons de changement de ligne

    If tMontant.Value <> 0 Then
        bLigneSuiv.Enabled = True
    Else
        bLigneSuiv.Enabled = False
    End If
    If tLigne.Value = 1 Then
        bLignePréc.Enabled = False
    Else
        bLignePréc.Enabled = True
    End If
End Sub

Private Sub bLignePréc_Click()
    If tLigne.Value = 1 Then
        Beep 'On ne peut pas reculer avant la ligne 1
        Exit Sub
    End If

    'Traiter la ligne en cours
    If tMontant.Value <> 0 Then 'Enregistrer la ligne s'il y a un montant
        Cells(Range("LigneÉditée").Value, 1) = tRéférence.Value
        Cells(Range("LigneÉditée").Value, 2) = tDate.Value
        Cells(Range("LigneÉditée").Value, 3) = tLigne.Value
        Cells(Range("LigneÉditée").Value, 7) = tItem.Value
        Cells(Range("LigneÉditée").Value, 8) = tPrix.Value
        Cells(Range("LigneÉditée").Value, 9) = tNombre.Value
        Cells(Range("LigneÉditée").Value, 10) = tMontant.Value
    End If

    'Passer à la ligne précédente
    Range("LigneÉditée").Value = Range("LigneÉditée").Value - 1

    'Édition de ligne existante
    tRéférence.Value = Cells(Range("LigneÉditée").Value, 1)
    tDate.Value = Cells(Range("LigneÉditée").Value, 2)
    tLigne.Value = Cells(Range("LigneÉditée").Value, 3)
    tItem.Value = Cells(Range("LigneÉditée").Value, 7)
    tPrix.Value = Cells(Range("LigneÉditée").Value, 8)
    tNombre.Value = Cells(Range("LigneÉditée").Value, 9)
    Call AfficherTot
    tItem.SetFocus 'Activer le 1er champ
End Sub

Private Sub bLigneSuiv_Click()
    'Traiter la ligne en cours
    If Val(tMontant.Value) = 0 Then 'Ne pas enregistrer ligne nulle
        Beep
        Exit Sub
    Else 'enregistrer la ligne
        Cells(Range("LigneÉditée").Value, 1) = tRéférence.Value
        Cells(Range("LigneÉditée").Value, 2) = tDate.Value
        Cells(Range("LigneÉditée").Value, 3) = tLigne.Value
        Cells(Range("LigneÉditée").Value, 7) = tItem.Value
        Cells(Range("LigneÉditée").Value, 8) = tPrix.Value
        Cells(Range("LigneÉditée").Value, 9) = tNombre.Value
        Cells(Range("LigneÉditée").Value, 10) = tMontant.Value
    End If

    'Passer à la ligne suivante
    Range("LigneÉditée").Value = Range("LigneÉditée").Value + 1

    If Range("LigneÉditée").Value > 899 Then 'Pas plus de 899 lignes par facture
        Range("LigneÉditée").Value = 899
    End If

    'Initialiser les champs
    If Cells(Range("LigneÉditée").Value, 1) <> "" Then
        'Édition de ligne existante
        tRéférence.Value = Cells(Range("LigneÉditée").Value, 1)
        tDate.Value = Cells(Range("LigneÉditée").Value, 2)
        tLigne.Value = Cells(Range("LigneÉditée").Value, 3)
        tItem.Value = Cells(Range("LigneÉditée").Value, 7)
        tPrix.Value = Cells(Range("LigneÉditée").Value, 8)
        tNombre.Value = Cells(Range("LigneÉditée").Value, 9)
        Call AfficherTot
    Else
        Call NouvelleLigne
    End If
    tItem.SetFocus 'Activer le 1er champ
End Sub

Commentaires:

Le traitement de facture:

Private Sub bEnregistrer_Click()
'Enregistrer la facture
Dim lLigne As Long

    If Val(tMontant.Value) <> 0 Then 'Enregistrer ligne en cours au besoin
        bLigneSuiv_Click
    End If

    lLigne = Range("LigneÉditée").Value = Range("LigneÉditée").Value

    'Information client
    Cells(lLigne, 1).Value = tRéférence.Value
    Cells(lLigne, 2).Value = tDate.Value
    Cells(lLigne, 3).Value = 0
    Cells(lLigne, 4).Value = tClient.Value
    Cells(lLigne, 5).Value = tAdresse1.Value
    Cells(lLigne, 6).Value = tAdresse2.Value

    'Sous-total
    lLigne = lLigne + 1
    Cells(lLigne, 1).Value = tRéférence.Value
    Cells(lLigne, 2).Value = tDate.Value
    Cells(lLigne, 3).Value = 900
    Cells(lLigne, 7).Value = "Sous-total"
    Cells(lLigne, 10).Value = Range("SousTotal").Value

    'TPS
    lLigne = lLigne + 1
    Cells(lLigne, 1).Value = tRéférence.Value
    Cells(lLigne, 2).Value = tDate.Value
    Cells(lLigne, 3).Value = 901
    Cells(lLigne, 7).Value = "TPS"
    Cells(lLigne, 10).Value = Round(Range("TPS").Value, 2)

    'TVQ
    lLigne = lLigne + 1
    Cells(lLigne, 1).Value = tRéférence.Value
    Cells(lLigne, 2).Value = tDate.Value
    Cells(lLigne, 3).Value = 902
    Cells(lLigne, 7).Value = "TVQ"
    Cells(lLigne, 10).Value = Round(Range("TVQ").Value, 2)

    'Total
    lLigne = lLigne + 1
    Cells(lLigne, 1).Value = tRéférence.Value
    Cells(lLigne, 2).Value = tDate.Value
    Cells(lLigne, 3).Value = 999
    Cells(lLigne, 7).Value = "Total"
    Cells(lLigne, 10).Value = Round(Range("Total").Value, 2)

    'Prochaine facture
    Range("RéférenceÉditée").Value = Range("ProchaineRéférence").Value

    'Prochaine ligne
    tLigne.Value = 0
    Call NouvelleLigne 'Sera ligne 1

    bAnnuler.Enabled = False
    bEnregistrer.Enabled = False

End Sub

Private Sub bAnnuler_Click()
    If MsgBox("Abandonner la facture en cours?", vbOKCancel, "Annuler facture") = vbOK Then
        Call annuler
    End If
End Sub

Private Sub bQuitter_Click()
    If Range("Total").Value <> 0 Then
        If MsgBox("Abandonner la facture en cours?", vbOKCancel, "Quitter sans enregistrer?") = vbOK Then
            Call annuler
            Unload Me
        End If
    Else
        Unload Me
    End If
End Sub

Commentaires:

Les procédures utilitaires:

Sub annuler()
Dim lLigne As Long

    If tLigne.Value = 1 Then 'Pas de facture
        'Annuler ligne en cours
        tLigne.Value = 0
        Call NouvelleLigne
        Exit Sub
    End If

    'Annuler les lignes de la facture annulée
    For lLigne = Val(Range("LigneÉditée").Value) - 1 To 1 Step -1
        If Cells(lLigne, 1).Value <> Val(tRéférence.Value) Then
            Exit For 'Terminé
        Else
            Range(Cells(lLigne, 1), Cells(lLigne, 10)).ClearContents
        End If
    Next

    'Annuler ligne en cours
    tLigne.Value = 0
    Call NouvelleLigne

    'Annuler entête
    tClient.Value = ""
    tAdresse1.Value = ""
    tAdresse2.Value = ""
End Sub

Sub NouvelleLigne()
    tLigne.Value = tLigne.Value + 1
    tItem.Value = ""
    tPrix.Value = ""
    tNombre.Value = ""
    Call AfficherTot
End Sub

Sub AfficherTot()
'Afficher les totaux de facture
'et activer les boutons appropriés.

    Calculate 'S'assurer d'avoir les bonnes valeurs
    lSousTotal.Caption = Range("SousTotal").Text
    lTPS.Caption = Range("TPS").Text
    lTVQ.Caption = Range("TVQ").Text
    lTotal.Caption = Range("Total").Text
    If Range("Total").Value > 0 Then
        bAnnuler.Enabled = True
        bEnregistrer.Enabled = True
    Else
        bAnnuler.Enabled = False
        bEnregistrer.Enabled = False
    End If
End Sub

Commentaires: Ces procédures contiennent des opérations qui sont utilisées par plusieurs autres procédures du formulaire.
On préfère regrouper ces opérations plutôt que les copier dans les différentes procédures qui les utilisent.

 

Suite: Objets et événements Excel