mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (2024)

Une «vraie-fausse» MsgBox avec boutons personnalisés et bien plus encore...

Voici donc le 3ème et dernier volet des articles que je consacre à la MsgBox, outil bien connu des développeurs VBA puisqu'il s'agit du premier moyen à disposition pour interagir avec l'utilisateur.

  • Dans un premier article intitulé Utilisation des MsgBox et m'adressant plus particulièrement aux débutants, j'ai souhaité aborder le B-A-BA en la matière et introduire les deux façons d'employer une MsgBox : utiliser la MsgBox en tant que méthode ou utiliser la MsgBox en tant que fonction, voilà bien toute une différence ! Cette introduction au sujet nous rappelle aussi que seuls 7 boutons prédéterminés sont mis à notre disposition : mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (1)mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (2) mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (3) mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (4) mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (5) mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (6) mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (7). Et il n'est d'ailleurs pas permis de les combiner entre eux comme on le souhaite...
  • Dans un deuxième article MsgBox personnalisées (API) , je vous ai présenté une façon d'obtenir une MsgBox avec boutons personnalisés en utilisant exclusivement l'Api Windows. Nous l'avions vu dans cet article, la méthode est certe efficace, mais elle souffre elle aussi de contraintes assez gênantes, à savoir : le nombre de boutons personnalisables est restreint à deux (avec toutefois la possibilité d'un bouton Annuler supplémentaire) et les libellés des boutons sont limités en taille (longueur).


L'objectif est donc de vous présenter cette fois ce que je pense être une solution viable et représentant une vraie alternative à l'existant.

    • Le nombre de boutons personnalisables ne doit pas être limité (un grand nombre de boutons peut toutefois nuire à l'esthétique et à la convivialité des dialogues avec l'utilisateur. Ce sera donc au développeur de fixer SA limite)
    • La taille des boutons devra être fonction de la taille des libellés choisis (et non l'inverse).
    • Le code doit pouvoir s'adapter aux souhaits du développeur sans avoir à être remanié. Un panel d'options débrayables doit donc être envisagé et l'ensemble doit rester le plus léger possible.
    • Le code ne doit pas remettre en cause les habitudes de développement et doit donc coller au plus près d'une MsgBox classique en terme d'appel de fonction et/ou méthode. Les nouveaux arguments mis à disposition devront donc être optionnels afin de permettre au développeur de se familiariser rapidement avec MsgBoxPerso. Par ailleurs, l'aide intuitive avec liste des arguments possibles lors de la saisie dans l'éditeur VBE serait bienvenues.
    • Tout comme la vraie MsgBox, la MsgBoxPerso devra pouvoir "capter" la réponse utilisateur pour permettre le bon déroulement du programme. Le choix d'une fonction personnalisée est donc requis pour retourner le choix de l'utilisateur.
    • L'apparence de la boîte de dialogue doit se rapprocher au plus près d'une MsgBox dite classique (position des boutons, icônes d'état, etc...)

A y réfléchir, je ne vois qu'une seule façon d'aborder le problème : il nous faut avoir recours à un Userform simulant une vraie MsgBox.

Mais bien évidemment, hors de question de créer un Userform «en dur» dans le projet puisque d"une part, celui-ci doit être réutilisable à souhait et d'autre part, son apparence devra varier en fonction de chaque appel dans le programme. Par ailleurs, un Userform «en dur» et les contrôles associés ajouteraient un poids non négligeable au projet et ne répondraient donc pas aux exigences fixées plus haut.

J'ai donc retenu le principe suivant : la création dynamique d'un Userform «jetable» après utilisation.

Le point qui m'a demandé le plus de recherches et de fil à retordre, ce fut : les icônes. En effet, comment insérer les icônes des vraies MsgBox dans un Userform, ce dernier étant, de plus, généré à la volée ?

Seule possibilité : le recours à l'Api Windows, mais sur ce seul point cette fois !

Il a donc fallu que je remonte les manches et que je m'y colle... N'étant pas un virtuose dans le domaine, ça n'a pas été très simple, mais j'y suis finalement parvenu !

Je résume la situation :

  • Il nous faut une fonction personnalisée avec ses arguments attendus.
  • A l'appel de cette fonctionn, un Userform sera généré à la volée (avec l'apparence de notre boîte de dialogue).
  • Le choix utilisateur sera ensuite retourné par cette fonction et le Userform détruit.

Comme vous allez le voir, cette méthode retenue m'a permis d'ajouter d'autres options intéressantes, à savoir :

Concernant le texte du message dans la boîte de dialogue :

      • Le changement de police et de la taille des caractères sera possible.
      • Les attributs Gras et Italic seront également disponibles.
      • L'alignement du texte à gauche, au centre ou à droite sera aussi permis au développeur.

Concernant la MsgBox elle-même (le Userform) :

      • Par défaut, la boîte de dialogue sera centrée sur l'écran. Mais il sera possible au développeur d'indiquer des coordonnées d'affichage précises pour en définir la position souhaitée.

L'objectif, c'est de vous permettre d'obtenir l'affichage de quelque chose comme ça, en ajoutant une seule ligne de code à votre projet :

mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (8)

Le code de la fonction personnalisée, je l'ai réalisé pour vous et je vous le fourni sous forme d'un module de code à insérer - tel quel - dans votre projet.

Vous retrouverez le module complet au bas de cet article (code à copier dans un module de code standard vierge ou fichier à télécharger et à importer directement dans votre projet dans l'éditeur VBE)

Au bas de cet article , vous pouvez télécharger le module de code .txt prêt à être importé dans votre projet VBA.

Je vous propose donc un simple module de code à copier ou importer dans votre projet VBA, module qui vous permettra d'obtenir facilement des MsgBox originales et rendre ainsi plus efficace l'interaction avec vos utilisateurs.

Une fois le module de code importé, tout est fait pour rendre l'utilisation la plus simple possible et pour rester au plus près de la syntaxe VBA que vous connaissez avec les MsgBox « classiques ». Le développeur que vous êtes ne sera donc pas dérouté par cette mise en oeuvre VBA.

mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (10) ATTENTION!

Le code VBA utilisé nécessite impérativement que l'option

«Faire confiance au projet Visual Basic»

soit cochée dans le menu Outils / Macro / Sécurité... / onglet Editeurs approuvés.

(sur Excel 2003)

L'appel de la fonction MsgBoxPerso est le plus proche possible de ce que vous connaissez déjà.


Syntaxe :

MsgBoxPerso(Prompt [, Title] [, Icon] [, Buttons] [, FontName] [, FontSize] [, FontStyle] [, txtAlign] [, X] [, Y])


Les arguments nommés sont décrits ci-dessous :

ArgumentsDescriptions
Prompt
  • Obligatoire. Chaîne de caractères représentant le texte de la boîte de dialogue.
Title
  • Facultatif. Chaîne de caractères valant titre de la boîte de dialogue.
    (à défaut, le nom de l'application sera pris pour titre de la MsgBox)
Icon
  • Facultatif. Peut être une des constantes VBA suivantes : 0 - vNoIcon (par défaut), 1 - vCritical mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (11), 2 - vQuestion mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (12), 3 - vExclamation mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (13) ou 4 - vInformation mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (14).
Buttons
  • Facultatif. Chaîne de caractères représentant les libellés des boutons.
    Chaque bouton sera séparé par un caractère | (pipe).
    Pour définir le bouton qui aura le focus (bouton par défaut), faites suivre son libellé d'un caractère * (étoile).
FontName
  • Facultatif. Chaîne de caractères représentant la police à utiliser pour le message. Ex : "Arial"
FontSize
  • Facultatif. Valeur numérique pour la taille des caractères du message. Valeurs admises : de 0 à 72.
FontStyle
  • Facultatif. Représente le style Normal, Gras ou Italic.
    Valeurs admises : 0 - vNormal (par défaut), 1 - vBold, 2 - vItalic ou 3 - vBoldItalic.
txtAlign
  • Facultatif. Représente l'alignement du texte du message.
    Valeurs admises : 0 - vLeft (par défaut), 1 - vCenter ou 2 - vRight.
X
  • Facultatif. Valeur numérique représentant la coordonnée X du coin supérieur gauche de la boîte de dialogue.
Y
  • Facultatif. Valeur numérique représentant la coordonnée Y du coin supérieur gauche de la boîte de dialogue.

Ainsi, pour obtenir la boîte de dialogue suivante :

mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (15)

La simple instruction suivante est suffisante (soit vRet une variable de type Integer) :

vRet = MsgBoxPerso("Mon message...", "Mon titre", vQuestion, "Bouton 1|Bouton 2")


Il convient ensuite de voir comment exploiter la réponse (vRet) de l'utilisateur. C'est ce que nous allons voir maintenant...

L'intérêt ici, est d'utiliser la procédure en tant que fonction afin de recevoir en retour le choix de l'utilisateur. Le terme boîte de «dialogue» prend ici tout son sens.

Comme notre MsgBox bien connue, la MsgBoxPerso retourne une valeur numérique nous indiquant le bouton sélectionné par l'utilisateur. On notera toutefois une différence avec la valeur retournée par la MsgBox originale :

La fonction personnalisée MsgBoxPerso retourne le numéro d'ordre du bouton cliqué par l'utilisateur, valeur de type Integer :

Si l'utilisateur clique sur ...
... voici la valeur retournée.
Bouton perso n°11
Bouton perso n°22
Bouton perso n°33
Etc...Etc...


En cas d'erreur, la fonction pourra toutefois retourner la valeur 0 (ça sera le cas notamment, si l'option «Faire confiance au projet VB» n'est pas cochée dans les paramètres de sécurité).

mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (16)

Le code nécessaire pour afficher cette MsgBoxPerso et en exploiter la réponse utilisateur peut ressembler à celui-ci :

Dim Message As String
Dim vRet As Integer

Message = "Mes cher(e)s ami(e)s," & vbLf & "Comment trouvez-vous cette mise en oeuvre ?"

vRet = MsgBoxPerso(Message, , vQuestion, "C'est très simple|Je n'ai rien compris|Sans avis")

Select Case vRet
Case 1
' ici le traitement si la réponse est "C'est très simple"
' ...
Case 2
' ici le traitement si la réponse est "Je n'ai rien compris"
' ...
Case 3
' ici le traitement si la réponse est "Sans avis"
' ...
End Select

Au bas de cet article , vous pouvez télécharger le module de code .txt prêt à être importé dans votre projet VBA.

Voici le contenu du module de code nécessaire à mDF_MsgBoxPerso :

Le module de code nécessaire à l'utilisation de mDF MsgBoxPerso

Option Explicit 
Option Private Module

' <<<<< LE PRESENT MODULE DE CODE EST A INSERER DANS VOTRE PROJET TEL QUEL ! >>>>>

' ***************************************************************************************
' * ATTENTION! *
' * *
' * Pour fonctionner, ce module nécessite que l'option "Faire confiance au projet *
' * Visual Basic" soit cochée dans le menu Outils / Macro / Sécurité... *
' ***************************************************************************************

'---------------------------------------------------------------------------------------
' Author: Didier FOURGEOT (myDearFriend!) - www.mdf-xlpages.com
' Date: 02/11/2008
' Topic : mDF MsgBoxPerso et boutons personnalisés
'---------------------------------------------------------------------------------------

' UTILISATION :
' -----------
' Dans votre code, vous ferez appel à la MsgBoxPerso comme vous le faites pour une MsgBox
' "classique", mais avec quelques arguments (optionnels) supplémentaires :

' SYNTAXE de la fonction :
' ----------------------
' R = MsgBoxPerso(Prompt, Title, Icon, Buttons, FontName, FontSize, FontStyle, txtAlign, X, Y)

' ARGUMENTS de la fonction :
' ------------------------
' * Prompt:Obligatoire. Il s'agit du texte de votre message.
' * Title: Facultatif. Titre de votre message.
' * Icon:Facultatif. Représente l'icône que vous voulez voir dans le message.
'Valeurs admises : 0 - vNoIcon (par défaut), 1 - vCritical,
'2 - vQuestion, 3 - vExclamation ou
'4 - vInformation.
' * Buttons: Facultatif. Chaîne de caractères représentant les libellés des boutons.
'Chaque bouton sera séparé par un caractère | (pipe).
'Pour définir le bouton qui aura le focus (bouton par défaut),
'faites suivre son libellé d'un caractère * (étoile).
'Exemple : Oui|Non*|Annuler
'("Non" sera le bouton par défaut)
' * FontName:Facultatif. Chaîne de caractères représentant la police à utiliser pour le
'message. Exemple : "Arial"
' * FontSize:Facultatif. Valeur numérique pour la taille des caractères du message.
'Valeurs admises : de 0 à 72.
' * FontStyle: Facultatif. Représente le style Normal, Gras ou Italic.
'Valeurs admises : 0 - vNormal (par défaut), 1 - vBold,
'2 - vItalic ou 3 - vBoldItalic.
' * TextAlign: Facultatif. Représente l'alignement du texte du message.
'Valeurs admises : 0 - vLeft (par défaut), 1 - vCenter ou
'2 - vRight.
' * X: Facultatif. Valeur numérique représentant la coordonnée X du coin supérieur
'gauche de la boîte de dialogue.
' * Y: Facultatif. Valeur numérique représentant la coordonnée Y du coin supérieur
'gauche de la boîte de dialogue.

' RETOUR de la fonction :
' ---------------------
' Utilisée en tant que fonction, MsgBoxPerso retourne une valeur de type Integer correspondant
' au numéro d'ordre du bouton cliqué par l'utilisateur.
'
' EXEMPLE :
'
' Dim vRet As Integer
' vRet = MsgBoxPerso("Quel jour de la semaine ?", , , "Lundi|Mardi|Mercredi|Jeudi|Vendredi")
'
' Si l'utilisateur choisit "Jeudi", alors la fonction retournera la valeur 4.

' INFOS COMPLEMENTAIRES :
' ---------------------
' On peut aussi faire l'appel à l'aide des arguments nommés :
' vRet = MsgBoxPerso(Prompt:="Etes-vous d'accord ?", Buttons:="Oui|Non|Sans avis")
'
' On peut aussi utiliser la macro comme méthode (sans retour de résultat) :
' MsgBoxPerso "C'est fini !", , , "Ok"

' **************************************************************************************

' Déclaration des fonctions Api Windows pour récupération des Icônes de MsgBox
Public Declare Function FindWindowA& Lib "user32" (ByVal lpClassName$, ByVal lpWindowName$)
Public Declare Function GetDC& Lib "user32" (ByVal hwnd&)
Public Declare Function LoadIconA& Lib "user32" (ByVal hInstance&, ByVal lpIconName&)
Public Declare Function DrawIcon& Lib "user32" (ByVal Hdc&, ByVal X&, ByVal Y&, ByVal hIcon&)
Public Declare Function DestroyIcon& Lib "user32" (ByVal hIcon&)
' Pour les arguments nommés de la fonction
Public Enum StyleIcon
vNoIcon
vCritical
vQuestion
vExclamation
vInformation
End Enum
Public Enum
TextAlign
vLeft
vCenter
vRight
End Enum
Public Enum
StyleFont
vNormal
vBold
vItalic
vBoldItalic
End Enum
'Variable publique pour "capter" la réponse utilisateur
Public VmsgBoxValue

Function MsgBoxPerso(ByVal Prompt, Optional ByVal Title, Optional ByVal Icon As _
StyleIcon = vNoIcon, Optional ByVal Buttons = "Ok", Optional ByVal FontName _
= "Tahoma", Optional ByVal FontSize = 10, Optional ByVal FontStyle As StyleFont _
= vNormal, Optional ByVal Align As TextAlign = vLeft, Optional ByVal X = 0, _
Optional ByVal Y = 0) As Integer
Dim
Btn
Dim Usf As Object, lblM As Object
Dim
Icn As StyleIcon
Dim TestVbp$
Dim LngMaxB%, MargBtn%, Margin%
Dim i As Byte, xBtn As Byte
'Test si "Faire confiance au projet VB" est coché
On Error Resume Next
TestVbp = ThisWorkbook.VBProject.Name
On Error GoTo 0
If TestVbp = vbNullString Then
MsgBox "L'utilisation de la MsgBoxPerso nécessite que l'option" _
& vbLf & """Faire confiance au projet Visual Basic"" soit cochée" _
& vbLf & "dans menu Options / Macro / Sécurité...", _
vbCritical, "mDF MsgBoxPerso..."
MsgBoxPerso = 0
Exit Function
End If

'
Btn = Split(Buttons, "|")
Icn = IIf(Icon < 1, 0, IIf(Icon > 4, 0, Icon + 32512))
Margin = IIf(Icn > 0, 45, 0)
FontStyle = Abs(Val(FontStyle))
If FontStyle > 3 Then FontStyle = 0
X = Abs(Val(X))
Y = Abs(Val(Y))
'Création du USF
Set Usf = ThisWorkbook.VBProject.VBComponents.Add(3)
'Title
If IsMissing(Title) Then Title = Application.Name
Usf.Properties("Caption") = Title
Usf.Properties("StartUpPosition") = IIf(X + Y = 0, 1, 0)
'Création zone de Prompt
Set lblM = Usf.Designer.Controls.Add("Forms.Label.1")
With lblM
.Move 0, 15
.WordWrap = False
.Font.Size = Application.Min(Abs(Val(FontSize)), 72)
.Font.Name = CStr(FontName)
.TextAlign = IIf(Align < 0, 1, IIf(Align > 2, 1, Align + 1))
.Font.Bold = FontStyle Mod 2 <> 0
.Font.Italic = FontStyle > 1
.AutoSize = True
.Caption = Prompt
.AutoSize = False
End With

'Création Buttons
xBtn = 1'Focus sur le premier bouton par défaut
For i = 0 To UBound(Btn)
With Usf.Designer.Controls.Add("Forms.CommandButton.1")
.AutoSize = True
.Caption = Application.Substitute(Btn(i), "*", "")
LngMaxB = Application.Max(LngMaxB, .Width)
.AutoSize = False
'On mémorise le bouton désigné par défaut (terminé par *)
If Right(Btn(i), 1) = "*" Then xBtn = i + 1
End With
Next
i
LngMaxB = Application.Max(LngMaxB, 50)
'Placement des contrôles sur le USF et insertion du code VBA évènementiel
With lblM
Usf.Properties("Width") = Application.Max((LngMaxB + 10) * _
(UBound(Btn) + 1) + 5, .Width + 24)
Usf.Properties("Height") = 85 + .Height
.Move Margin + 10, 15, Usf.Properties("Width") - 24, .Height
End With
With
Usf
MargBtn = (.Properties("Width") - (LngMaxB + 5) * (UBound(Btn) + 1)) 2
'Procédure UserForm_Activate()
With .CodeModule
.InsertLines .CountOfLines + 1, "Private Sub UserForm_Activate(): " _
& "Dim hwnd&, hIcon&: DoEvents:" _
& "hwnd = FindWindowA(vbNullString, Me.Caption):" _
& "hIcon = LoadIconA(0&," & Icn & "):" _
& "DrawIcon GetDC(hwnd), 26, 24, hIcon:" _
& "DestroyIcon hIcon: Me.Controls(""CommandButton" & xBtn & """)" _
& ".Setfocus:Beep:End Sub"
End With
For
i = 0 To UBound(Btn)
.Designer.Controls("CommandButton" & i + 1).Move Margin + MargBtn + _
(LngMaxB + 5) * i, lblM.Top + lblM.Height + 22, LngMaxB, 20
'Procédures évènementielles liées aux Buttons
With .CodeModule
.InsertLines .CountOfLines + 1, "Sub CommandButton" & i + 1 _
& "_Click():VmsgBoxValue =" & i + 1 & " :Unload Me:End Sub"
End With
Next
i
Usf.Properties("Width") = Usf.Properties("Width") + Margin
'Interdire fermeture par la croix
With Usf.CodeModule
.InsertLines .CountOfLines + 1, "Private Sub UserForm_QueryClose(Cancel " _
& "As Integer, CloseMode As Integer):Cancel = CloseMode = 0:End Sub"
End With
'Affichage la MsgBoxPerso, puis auto-destruction du USF
If X + Y > 0 Then
Usf.Properties("Left") = X
Usf.Properties("top") = Y
End If
VBA.UserForms.Add(.Name).Show
End With
ThisWorkbook.VBProject.VBComponents.Remove Usf
MsgBoxPerso = VmsgBoxValue
End Function

Pour illustrer les différentes possibilités et l'utilisation du module de code téléchargeable ci-dessous , vous trouverez également en Section Téléchargements - catégorie Classeurs Exemples / API Windows, le fichier mDF MsgBoxPerso Démo .

Pour toutes vos questions ou si vous rencontrez des difficultés, n'hésitez pas à rejoindre nos Forums de Discussions !

mDF MsgBoxPerso « le Retour » - Tutoriels & Astuces Excel > L'API Windows (2024)
Top Articles
Latest Posts
Article information

Author: Kelle Weber

Last Updated:

Views: 5982

Rating: 4.2 / 5 (73 voted)

Reviews: 80% of readers found this page helpful

Author information

Name: Kelle Weber

Birthday: 2000-08-05

Address: 6796 Juan Square, Markfort, MN 58988

Phone: +8215934114615

Job: Hospitality Director

Hobby: tabletop games, Foreign language learning, Leather crafting, Horseback riding, Swimming, Knapping, Handball

Introduction: My name is Kelle Weber, I am a magnificent, enchanting, fair, joyous, light, determined, joyous person who loves writing and wants to share my knowledge and understanding with you.