mDF MsgBoxPerso « le Retour »
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 : . 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.
Les contraintes fixées
- 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...)
Méthode retenue
- 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.
Améliorations supplémentaires
- 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.
- 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
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 :
Le code de cette fonction personnalisée
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)
La mise en oeuvre
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.
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)
|
MsgBoxPerso : syntaxe et arguments
Syntaxe :
MsgBoxPerso(Prompt [, Title] [, Icon] [, Buttons] [, FontName] [, FontSize] [, FontStyle] [, txtAlign] [, X] [, Y])
Les arguments nommés sont décrits ci-dessous :
Arguments | Descriptions |
Prompt |
|
Title |
|
Icon |
|
Buttons |
|
FontName |
|
FontSize |
|
FontStyle |
|
txtAlign |
|
X |
|
Y |
|
Ainsi, pour obtenir la boîte de dialogue suivante :
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...
Valeur de retour
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°1 | 1 |
Bouton perso n°2 | 2 |
Bouton perso n°3 | 3 |
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é).
Exemple d'utilisation
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
Le module de code
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 :
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
Démonstration
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 .
Autres articles dans cette catégorie | Publié le | Vues |
---|---|---|
mDF MsgBoxPerso « le Retour » | 02-11-2008 | 18531 |
MsgBox personnalisées (API) | 18-11-2007 | 62410 |
API Windows - Introduction | 03-07-2006 | 12801 |