FAQ Excel

FAQ ExcelConsultez toutes les FAQ
Nombre d'auteurs : 46, nombre de questions : 845, dernière mise à jour : 30 mars 2022
Sommaire→Les macros VBA→Les UserForm et les contrôles→Les UserForms- Comment utiliser les UserForm ?
- Comment trouver le Handle d'une Userform ?
- Comment inhiber ou masquer le bouton "Fermer" d'une UserForm ?
- Comment masquer la barre de titre d'une UserForm ?
- Comment créer un UserForm dynamiquement ?
- Comment adapter les dimensions d'un UserForm à la taille de l'écran ?
- Comment afficher une image PNG dans un UserForm ?
- Comment ajouter un bouton de réduction dans les UserForms ?
- Comment appliquer une transparence dans un UserForm ?
- Comment créer plusieurs instances d'un UserForm ?
- Est-il possible d'afficher une barre d'outils dans un UserForm ?
- Comment ajouter un icône dans la barre de Caption ?
- A quoi sert l'évènement UserForm_Layout ?
- Comment changer la couleur du texte dans la barre de caption ?
- Pourquoi la boîte à outils est vide dans l'éditeur de macros ?
- Comment boucler sur les userforms et leurs contrôles depuis l'éditeur VBE ?
Consultez le tutoriel pour utiliser les UserForm pour en VBA Excel.
De nombreuses fonctions de l'API Win32, agissant sur les fenêtres, réclament en paramètre le handle (ou identificateur)
de la dite fenêtre.
Malheureusement certains applicatifs tels Excel, Word... ne permettent pas de récupérer cette valeur.
la fonction FindWindowA, de l'API Win32, permet de connaître le handle d'une fenêtre à partir de son titre.
Private Declare Function FindWindowA Lib "user32" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Sub UserForm_Initialize()
Dim MeHwnd As Long
MeHwnd = FindWindowA(vbNullString, Me.Caption)
MsgBox "le Handle de l'Userform " & Me.Caption & " est : 0x" & Hex(MeHwnd)
End Sub
Vous pouvez avoir besoin d'empêcher la fermeture d'une userform par la croix système.
2 solutions vous sont proposées ci-dessous :
1) La plus simple: inhiber l'action de la croix de fermeture dans l'évènement QueryClose de la UserForm :
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = vbFormControlMenu Then Cancel = True
End Sub2) La plus jolie: masquer le bouton de fermeture de la UserForm :
'-- Dans la partie Déclaration de la Form :
Private Const SC_CLOSE = &HF060&
Private Const MF_BYCOMMAND = &H0&
Private Declare Function GetSystemMenu Lib "user32" _
(ByVal hwnd As Long, ByVal bRevert As Long) As Long
Private Declare Function RemoveMenu Lib "user32" _
(ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Private Declare Function FindWindowA Lib "user32" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
'-- Dans l'évènement Initialise de la Form :
Private Sub UserForm_Initialize()
Dim hSysMenu As Long
Dim MeHwnd As Long
MeHwnd = FindWindowA(vbNullString, Me.Caption)
If MeHwnd > 0 Then
hSysMenu = GetSystemMenu(MeHwnd, False)
RemoveMenu hSysMenu, SC_CLOSE, MF_BYCOMMAND
Else
MsgBox "Handle de " & Me.Caption & " Introuvable", vbCritical
End If
End SubIl faut utiliser les fonctions de l'API Windows : SetWindowLong, SetWindowPos, GetWindowRect, GetWindowLong et hSysMenu et, pour le cas d'Excel ou Word qui ne donne pas accès au handle de la fenêtre : FindWindowA...
Déclarations à placer dans un module standard :
Public Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Const GWL_STYLE = (-16)
Const WS_CAPTION = &HC00000
Const SWP_FRAMECHANGED = &H20
Public Declare Function FindWindowA Lib "user32" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public Declare Function GetWindowRect Lib "user32" _
(ByVal hwnd As Long, lpRect As RECT) As Long
Public Declare Function GetWindowLong Lib "user32" Alias _
"GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Public Declare Function SetWindowLong Lib "user32" Alias _
"SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long
Public Declare Function SetWindowPos Lib "user32" _
(ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, _
ByVal y As Long, ByVal cx As Long, ByVal cy As Long, _
ByVal wFlags As Long) As LongFonction pour afficher ou masquer la barre de titre d'une UserForm (vous pouvez aussi la placer dans le module) :
Sub AfficheTitleBarre(stCaption As String, pbVisible As Boolean)
Dim vrWin As RECT
Dim style As Long
Dim lHwnd As Long
'- Recherche du handle de la fenêtre par son Caption
lHwnd = FindWindowA(vbNullString, stCaption)
If lHwnd = 0 Then
MsgBox "Handle de " & stCaption & " Introuvable", vbCritical
Exit Sub
End If
GetWindowRect lHwnd, vrWin
style = GetWindowLong(lHwnd, GWL_STYLE)
If pbVisible Then
SetWindowLong lHwnd, GWL_STYLE, style Or WS_CAPTION
Else
SetWindowLong lHwnd, GWL_STYLE, style And Not WS_CAPTION
End If
SetWindowPos lHwnd, 0, vrWin.Left, vrWin.Top, vrWin.Right - vrWin.Left, _
vrWin.Bottom - vrWin.Top, SWP_FRAMECHANGED
End SubDans l'évènement Initialize de l'UserForm concernée :
Private Sub UserForm_Initialize()
'On passe en arguments :
' - le titre de la fenêtre
' - False pour masquer la barre de titre
AfficheTitleBarre Me.Caption, False
End SubCet exemple crée un UserForm et une ListBox par macro, ainsi qu'une macro évènementielle "Click()" pour la ListBox.
Option Explicit
Dim Usf As Object
Sub lancementProcedure()
Dim X As Object
Dim i As Integer
Dim strList As String
strList = "ListBox1"
Set X = creationUserForm_Et_listBox_Dynamique(strList)
For i = 1 To 10
X.Controls(strList).AddItem "Donnee " & i
Next i
X.Show
ThisWorkbook.VBProject.VBComponents.Remove Usf
Set Usf = Nothing
End SubFunction creationUserForm_Et_listBox_Dynamique(nomListe As String) As Object
Dim ObjListBox As Object
Dim j As Integer
Set Usf = ThisWorkbook.VBProject.VBComponents.Add(3)
With Usf
.Properties("Caption") = "Mon UserForm"
.Properties("Width") = 300
.Properties("Height") = 200
End With
Set ObjListBox = Usf.Designer.Controls.Add("Forms.ListBox.1")
With ObjListBox
.Left = 20: .Top = 10: .Width = 90: .Height = 140
.Name = nomListe
.Object.ColumnCount = 1
.Object.ColumnWidths = 70
End With
With Usf.CodeModule
j = .CountOfLines
.InsertLines j + 1, "Sub " & nomListe & "_Click()"
.InsertLines j + 2, "If Not " & nomListe & ".ListIndex = -1 Then MsgBox " & nomListe
.InsertLines j + 3, "End Sub"
End With
VBA.UserForms.Add (Usf.Name)
Set creationUserForm_Et_listBox_Dynamique = UserForms(UserForms.Count - 1)
End FunctionPrivate Sub UserForm_Activate()
With Me
.StartUpPosition = 3
.Width = Application.Width
.Height = Application.Height
.Left = 0
.Top = 0
End With
End SubLe contrôle Image ne permet pas d'afficher
le type de fichier PNG.
Une solution consiste à visualiser l'image dans un contrôle WebBrowser.
Private Sub UserForm_Initialize()
Dim S As String
Dim Hauteur As Long, Largeur As Long
Hauteur = WebBrowser1.Height
Largeur = WebBrowser1.Width
S = "C:\Dossier\LeChat.png"
WebBrowser1.Navigate _
"ABOUT:<HTML><HEAD><body><IMG WIDTH=" & Largeur & " HEIGHT=" & Hauteur & _
" SRC='" & S & "'</IMG></BODY></HTML>"
End Sub
En utilisant la procédure suivante, un bouton de réduction est ajouté à côté de la croix de fermeture.
L'UserForm se réduira, en bas et à gauche de l'écran, lorsque vous cliquerez dessus.
Placez cette première macro dans un module standard. Vous utiliserez cette macro pour lancer l'UserForm.
Option Explicit
Sub LanceUSF()
UserForm1.Show 0
End SubEnsuite, placez ce code dans le module objet du UserForm :
Option Explicit
Private Declare Function FindWindowA& Lib "User32" _
(ByVal lpClassName$, ByVal lpWindowName$)
Private Declare Function EnableWindow& Lib "User32" _
(ByVal hWnd&, ByVal bEnable&)
Private Declare Function GetWindowLongA& Lib "User32" _
(ByVal hWnd&, ByVal nIndex&)
Private Declare Function SetWindowLongA& Lib "User32" _
(ByVal hWnd&, ByVal nIndex&, ByVal dwNewLong&)
Private Sub UserForm_Initialize()
Dim hWnd As Long
hWnd = FindWindowA(vbNullString, Me.Caption)
SetWindowLongA hWnd, -16, GetWindowLongA(hWnd, -16) Or &H20000
End Sub
Private Sub UserForm_Activate()
Dim hWnd As Long
hWnd = FindWindowA("XLMAIN", Application.Caption)
EnableWindow hWnd, 1
End SubCet exemple permet de paramétrer un niveau de transparence (de 0 à 100%) dans un UserForm.
Utilisez le mot clé New pour créer plusieurs instances d'une classe particulière. Votre UserForm peut ainsi être dupliqué
plusieurs fois à l'écran.
Cet exemple est une traduction d'un article Microsoft.
'--- Dans un module standard --------
Option Explicit
Option Base 1
'Compte les instances d'UserForms.
Public mycount As Integer
'Tableau contenant les objets UserForm.
Public MyForms() As UserForm1
Sub New_UserForms()
'Affiche l'UserForm.
UserForm1.Show
End Sub
'-----------------------------------'--- Dans un UserForm nommé UserForm1 -------
'La forme doit contenir 3 CommandButton nommés :
'cmdNewForm (caption = Nouveau)
'cmdFormCaption (caption = Affiche la propriété caption du UserForm)
'cmdClose (caption = fermeture)
'Une ListBox nommée :
'ListBox1
Option Explicit
Private Sub cmdNewForm_Click()
mycount = mycount + 1
'Redéfinit la taille du tableau e , incrémentant d'une unité.
ReDim Preserve MyForms(mycount)
'Crée une nouvelle instance UserForm1.
Set MyForms(mycount) = New UserForm1
'Ajoute le numéro d'instance à la propriété 'Caption' du UserForm.
MyForms(mycount).Caption = "instance " & mycount
MyForms(mycount).cmdClose.Caption = "Masquer la forme"
'Ajoute un élément dans la ListBox.
UserForm1.ListBox1.AddItem mycount
End Sub
Private Sub cmdFormCaption_click()
'Affiche la propriété 'Caption' du UserForm actif.
MsgBox Me.Caption
End Sub
Private Sub cmdClose_Click()
'Masque l'instance active.
Me.Hide
End Sub
Private Sub ListBox1_MouseUp _
(ByVal Button As Integer, ByVal Shift As Integer, _
ByVal X As Single, ByVal Y As Single)
'Affiche l'instance sélectionnée.
MyForms(UserForm1.ListBox1.ListIndex + 1).Show
End Sub
Private Sub UserForm_QueryClose _
(Cancel As Integer, CloseMode As Integer)
'Gère l'absence de UserForm
On Error Resume Next
'Indiquez n'importe quelle valeur (Integer) autre que 0 pour désactiver
'l'utilisation de la croix de fermeture ("X") du UserForm.
Cancel = 1
End SubCet exemple suppose que l'UserForm contient un label nommé Label1. La barre d'outils s'affiche lorsque vous cliquez sur ce label.
Option Explicit
Dim X As Single
Dim Y As Single
'Création de la barre d'outils lors du lancement du UserForm
Private Sub UserForm_Initialize()
Dim Barre As CommandBar
Set Barre = CommandBars.Add("MenuUSF", msoBarPopup, False, True)
With Barre.Controls.Add(msoControlButton, 1, , , True)
.Caption = "Menu 01"
.FaceId = 50
'La procédure va appeler une macro nommée "Macro1", lorsque vous cliquerez
'sur le bouton.
.OnAction = "Macro1"
End With
With Barre.Controls.Add(msoControlButton, 2, , , True)
.Caption = "Menu 02"
.FaceId = 49
'La procédure va appeler une macro nommée "Macro2", lorsque vous cliquerez
'sur le bouton.
.OnAction = "Macro2"
End With
With Me
X = (.Width - .InsideWidth) / 2 + 8
Y = .Height - .InsideHeight - X + 24
End With
End Sub
'Affiche la barre d'outils lorsque vous cliquez sur le label.
Private Sub Label1_Click()
Dim PosX As Single, PosY As Single
PosX = (Me.Left + X + Label1.Left) * 4 / 3
PosY = (Me.Top + Y + Label1.Top) * 4 / 3
Application.CommandBars("MenuUSF").ShowPopup PosX, PosY
End Sub
'Supprime la barre d'outils lors de la fermeture du UserForm
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
On Error Resume Next
CommandBars("MenuUSF").Delete
End SubAjoutez ces deux macros dans un module standard :
Option Explicit
Sub Macro1()
MsgBox "Essai 01"
End Sub
Sub Macro2()
MsgBox "Essai 02"
End SubL'icône va s'afficher dans l'angle supérieur gauche de la forme.
Option Explicit
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SendMessageA Lib "user32" _
(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Integer, _
ByVal lParam As Long) As Long
Private Declare Function ExtractIconA Lib "shell32.dll" _
(ByVal hInst As Long, ByVal lpszExeFileName As String, ByVal nIconIndex As Long) As Long
Private Sub UserForm_Initialize()
Dim Fichier As String
Dim x As Long
'Chemin et nom du fichier icône à afficher
Fichier = "C:\Documents and Settings\mimi\dossier\bouton.ICO"
'Vérifie si le fichier existe
If Dir(Fichier) = "" Then Exit Sub
x = ExtractIconA(0, Fichier, 0)
SendMessageA FindWindow(vbNullString, Me.Caption), &H80, False, x
End SubL'évènement Layout est déclenché lorsque vous changez la position du UserForm.
Cet exemple définit la position de la boîte de dialogue et empêche de le déplacer à l'écran.
Private Sub UserForm_Layout()
Application.ScreenUpdating = False
'Définit la position horizontale de l'USF
Me.Left = 200
'Définit la position verticale de l'USF
Me.Top = 50
Application.ScreenUpdating = True
End Sub
Cette opération est réalisable en utilisant les API de Windows :
GetSysColor pour mémoriser la couleur initiale,
SetSysColors pour spécifier la nouvelle couleur.
Option Explicit
'Texte dans la barre de caption
Const COLOR_CAPTIONTEXT = 9
Private Declare Function GetSysColor Lib "user32" _
(ByVal nIndex As Long) As Long
Private Declare Function SetSysColors Lib "user32" _
(ByVal nChanges As Long, lpSysColor As Long, _
lpColorValues As Long) As Long
Dim EnrCouleur As Long
'Modifie la couleur du texte lors del'affichage du UserForm
Private Sub UserForm_Activate()
Me.Caption = "Mon texte perso"
'Memorise la couleur initiale
EnrCouleur = GetSysColor(COLOR_CAPTIONTEXT)
'Modife la couleur
SetSysColors 1, COLOR_CAPTIONTEXT, RGB(90, 0, 125)
End Sub
'Réinitialise la couleur
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
SetSysColors 1, COLOR_CAPTIONTEXT, EnrCouleur
End Sub
Les fichiers .exd peuvent être à l'origine du problème. Ces fichiers sont généralement stockés dans le répertoire :
C:\Documents and Settings\nom_utilisateur\Application Data\Microsoft\Forms
Les fichiers EXD sont créés lorsque vous ajoutez des contrôles dans la boîte à outils et permettent d'accélérer le démarrage de vos classeurs par la mise en cache des informations du contrôle.
Si la boîte à outils reste vide, faites le ménage dans ce répertoire: Supprimez les fichiers EXD et BOX.
Les fichiers RefEdit.exd et EXCEL.box, qui sont utilisés pour les contrôles par défaut, seront recréés automatiquement lors de la réouverture de l'application. Il vous restera ensuite à ajouter les autres contrôles manuellement (Clic droit sur la boîte de dialogue / contrôles supplémentaires).
Il est parfois utile de lister les noms des contrôles et leur contenu lorsque que vous travaillez
sur des projets volumineux.
Cette procédure montre comment boucler sur les userforms du classeur, puis sur tous les contrôles
afin d'identifier les labels.
Nécessite d'activer la référence Microsoft Visual Basic for Applications Extensibility 5.3.
Dim VBCmp As VBComponent
Dim Ctrl As Control
'Boucle sur les composants du classeur
For Each VBCmp In ThisWorkbook.VBProject.VBComponents
'S'il s'agit d'un UserForm
If VBCmp.Type = 3 Then
Debug.Print VBCmp.Name
'Boucle sur les contrôles des userforms
For Each Ctrl In VBCmp.Designer.Controls
'S'il s'agit d'un label
If TypeName(Ctrl) = "Label" Then _
Debug.Print Ctrl.Name & " / " & Ctrl.Caption
Next Ctrl
Debug.Print "-----"
End If
Next VBCmp


