FAQ Excel
FAQ ExcelConsultez toutes les FAQ
Nombre d'auteurs : 46, nombre de questions : 845, dernière mise à jour : 30 mars 2022
- 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
Sub
2) 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
Sub
Il 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
Long
Fonction 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
Sub
Dans 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
Sub
Cet 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
Sub
Function
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
Function
Private
Sub
UserForm_Activate
(
)
With
Me
.StartUpPosition
=
3
.Width
=
Application.Width
.Height
=
Application.Height
.Left
=
0
.Top
=
0
End
With
End
Sub
Le 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
Sub
Ensuite, 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
Sub
Cet 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
Sub
Cet 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
Sub
Ajoutez ces deux macros dans un module standard :
Option
Explicit
Sub
Macro1
(
)
MsgBox
"Essai 01"
End
Sub
Sub
Macro2
(
)
MsgBox
"Essai 02"
End
Sub
L'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
Sub
L'é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