FAQ Visual Basic
FAQ Visual Basic Consultez toutes les FAQ
Nombre d'auteurs : 50, nombre de questions : 300, dernière mise à jour : 15 juin 2021
- Comment ajouter dynamiquement des contrôles dans une form ?
- Comment empêcher la fermeture d'une form ?
- Comment désactiver le bouton de fermeture sur une form ?
- Comment activer/désactiver les boutons "Réduire" et "Agrandir" d'une form ?
- Comment faire pour que ma form soit toujours au premier plan ?
- Comment faire passer une MDIChild form au 1er plan en cliquant sur un bouton dans une ToolBar?
- Comment savoir quelles forms sont chargées en mémoire ?
- Comment redimensionner les contrôles quand la form est redimensionnée ?
- Comment passer des paramètres à une form lors de son ouverture ?
- Comment permettre le déplacement d'une form qui n'a pas de barre de titre ?
- Comment énumérer les contrôles d'une form dans une boucle ?
- Comment savoir si un contrôle appartient à un groupe de contrôles ?
- Comment ouvrir une même form plusieurs fois ?
- Comment afficher une form dont les dimensions ne dépendent pas de la résolution ?
- Comment détecter le mouvement d'une form ?
- Comment centrer une feuille MDI fille par rapport à la MDI mère ?
- Comment régler la transparence d'une fenêtre ?
- Comment faire réapparaître le "Underscore _ " dans les menus de ma form ?
Vous avez plusieurs solutions possibles. La première est de poser un contrôle sur la form et de lui donner un index, par exemple 0. Pour créer les autres contrôles à l'exécution, il faut les charger avec Load, les positionner, puis les rendre visibles. Vous pouvez ensuite détruire ces contrôles avec Unload. Pour tester l'exemple suivant, placez un textbox sur une form et donnez-lui l'index 0. Ces quelques lignes font apparaître 9 autres textbox :
Dim
i As
Long
For
i =
1
To
9
Load Text1
(
i)
Text1
(
i).Top
=
Text1
(
i -
1
).Top
+
Text1
(
0
).Height
+
60
Text1
(
i).Visible
=
True
Next
Vous pouvez ensuite les détruire :
Dim
i As
Long
For
i =
1
To
9
Unload Text1
(
i)
Next
Une autre façon de procéder consiste à ajouter un élément à la collection Controls de la form. Auparavant il faut avoir déclaré votre contrôle dans la partie Déclarations du module de la form. Une fois la déclaration ajoutée, vous pourrez sélectionner votre contrôle dans la liste déroulante au-dessus de l'éditeur de code, comme si le contrôle avait été posé sur la form. Exemple pour un textbox :
Dim
WithEvents TextBoxDynamique As
VB.TextBox
Nous pouvons alors créer le contrôle, le placer, le dimensionner et le rendre visible :
Set
TextBoxDynamique =
Me.Controls.Add
(
"VB.TextBox"
, "txtDynamic"
) 'txtDynamic est le nom du textbox
TextBoxDynamique.Left
=
2000
TextBoxDynamique.Top
=
1000
TextBoxDynamique.Width
=
1500
TextBoxDynamique.Height
=
70
TextBoxDynamique.Visible
=
True
Pour supprimer le contrôle :
Me.Controls.Remove
"txtDynamic"
Set
TextBoxDynamique =
Nothing
Quand la fermeture d'une form a été demandée, elle reçoit l'évènement QueryUnload. Dans l'exemple suivant, la form ne se ferme pas, sauf si la demande de fermeture est due à la commande Unload :
Private
Sub
Form_QueryUnload
(
Cancel As
Integer
, UnloadMode As
Integer
)
If
UnloadMode <>
vbFormCode Then
Cancel =
1
End
Sub
Placez tout d'abord ces déclarations dans le module 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
Puis ces quelques lignes dans la procédure Form_Load :
Dim
hSysMenu As
Long
hSysMenu =
GetSystemMenu
(
Me.hwnd
, False
)
RemoveMenu hSysMenu, SC_CLOSE, MF_BYCOMMAND
Les propriétés MaxButton et MinButton d'une form VB ne sont pas accessibles en mode exécution.
Cette astuce permet de les modifier par le code.
NOTA : valable uniquement à la création de la Form, dans la procédure Form_Load. Une fois la form chargée, il n'est plus possible de modifier ses options de menu
'-- Déclarations
Private
Const
GWL_STYLE As
Long
=
-
16
Private
Const
WS_MAXIMIZEBOX =
&
H10000
Private
Const
WS_MINIMIZEBOX =
&
H20000
Private
Const
WS_SYSMENU =
&
H80000
Private
Declare
Function
GetWindowLong Lib
"user32"
Alias "GetWindowLongA"
_
(
ByVal
hwnd As
Long
, ByVal
nIndex As
Long
) As
Long
Private
Declare
Function
SetWindowLong Lib
"user32"
Alias "SetWindowLongA"
_
(
ByVal
hwnd As
Long
, ByVal
nIndex As
Long
, _
ByVal
dwNewLong As
Long
) As
Long
Pour activer les boutons :
Private
Sub
Form_Load
(
)
SetWindowLong hwnd, GWL_STYLE, GetWindowLong
(
Me.hwnd
, GWL_STYLE) Or
WS_MAXIMIZEBOX
SetWindowLong hwnd, GWL_STYLE, GetWindowLong
(
Me.hwnd
, GWL_STYLE) Or
WS_MINIMIZEBOX
End
Sub
Pour désactiver les boutons :
Private
Sub
Form_Load
(
)
SetWindowLong hwnd, GWL_STYLE, GetWindowLong
(
Me.hwnd
, GWL_STYLE) Xor
WS_MAXIMIZEBOX
SetWindowLong hwnd, GWL_STYLE, GetWindowLong
(
Me.hwnd
, GWL_STYLE) Xor
WS_MINIMIZEBOX
End
Sub
Ajoutez ces déclarations dans le module de votre form :
Private
Const
SWP_NOMOVE =
2
Private
Const
SWP_NOSIZE =
1
Private
Const
HWND_TOPMOST =
-
1
Private
Const
HWND_NOTOPMOST =
-
2
;
Private
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
Et placez cette ligne dans la procédure Form_Load :
SetWindowPos Me.hwnd
, HWND_TOPMOST, 0
, 0
, 0
, 0
, SWP_NOMOVE Or
SWP_NOSIZE
Pour annuler, placez cette ligne dans la procédure adéquate :
SetWindowPos Me.hwnd
, HWND_NOTOPMOST, 0
, 0
, 0
, 0
, SWP_NOMOVE Or
SWP_NOSIZE
Pour placer le nom de la MDIChild Form sur un bouton dans la ToolBar, il faut utiliser la fonction CallByName. Pour le passage au premier plan, on utilise Zorder. Info : Le contrôle ToolBar se trouve dans Microsoft Windows Common Controls 5.0 (SP2) ou Microsoft Windows Common 6.0 (SP4) suivant le Service Pack VB installé. Dans Form1, placez ce code :
Public
FormName As
Object
Private
Sub
Form_Load
(
)
Set
FormName =
Me
MDIForm1.Toolbar1.Buttons.Add
1
, "Key1"
, Me.Name
End
Sub
Dans MDIForm1, placez ce code :
Private
Sub
Toolbar1_ButtonClick
(
ByVal
Button As
MSComctlLib.Button
)
Select
Case
Button.Key
Case
"Key1"
CallByName FormName, "ZOrder"
, VbMethod, 0
End
Select
End
Sub
Pour retirer le bouton lors de la fermeture de la MDIChild Form, ajouter ce code dans Form1 :
Private
Sub
Form_Unload
(
Cancel As
Integer
)
MDIForm1.Toolbar1.Buttons.Remove
"Key1"
End
Sub
Elles sont dans la collection Forms. Ainsi cette boucle décharge toutes les forms :
Dim
f As
Form
For
Each
f In
Forms
Unload f
Next
Placez ce code source dans le module de votre form. Le principe consiste ici à déplacer et redimensionner les contrôles afin qu'ils soient disposés de la même façon. Ainsi si la form a subit un agrandissement de 4 * 3, toutes les distances sont multipliées par les mêmes facteurs.
Une autre méthode, plus souvent utilisée, consiste à agrandir seulement les contrôles principaux, et à garder les mêmes dimensions pour les contrôles plus petits (boutons, listes déroulantes, etc...). Mais dans ce cas un code source spécifique doit être écrit pour chacune de vos forms.
(La fonction ExistProperty est disponible dans la FAQ VB, voir le lien ci-dessous)
Dim
lar As
Long
, lng As
Long
Private
Sub
Form_Load
(
)
lng =
Me.Width
lar =
Me.Height
End
Sub
Private
Sub
Form_Resize
(
)
Dim
ctl As
Control
If
(
Me.WindowState
=
1
) Then
Exit
Sub
For
Each
ctl In
Me.Controls
If
TypeOf ctl Is
ComboBox Then
'Les comboboxes ont leur propriété Height en lecture seule
ctl.Move
ctl.Left
*
Me.Width
/
lng, ctl.Top
*
Me.Height
/
lar, ctl.Width
*
Me.Width
/
lng
Else
If
ExistProperty
(
ctl, "Width"
) And
ExistProperty
(
ctl, "Height"
) Then
ctl.Move
ctl.Left
*
Me.Width
/
lng, ctl.Top
*
Me.Height
/
lar, _
ctl.Width
*
Me.Width
/
lng, ctl.Height
*
Me.Height
/
lar
End
If
End
If
Next
lng =
Me.Width
lar =
Me.Height
End
Sub
Lien : Comment savoir si une propriété existe pour un contrôle ?
La méthode Show de la classe Form ne vous permet pas d'ajouter vos propres paramètres. L'astuce consiste à passer par des variables ou des propriétés publiques. Dans l'exemple suivant, les variables privées m_chaine1 et m_chaine2 sont accessibles en lecture/écriture depuis l'extérieur par l'intermédiaire des propriétés Chaine1 et Chaine2. La méthode publique Init() peut aussi être appelée afin d'initialiser ces propriétés.
Module de la Form :
Private
m_chaine1 As
String
Private
m_chaine2 As
String
Public
Sub
Init
(
strChaine1 As
String
, strChaine2 As
String
)
Chaine1 =
strChaine1
Chaine2 =
strChaine2
End
Sub
Public
Property
Get
Chaine1
(
) As
String
Chaine1 =
m_chaine1
End
Property
Property
Let
Chaine1
(
strChaine As
String
)
m_chaine1 =
strChaine
End
Property
Property
Get
Chaine2
(
) As
String
Chaine2 =
m_chaine2
End
Property
Property
Let
Chaine2
(
strChaine As
String
)
m_chaine2 =
strChaine
End
Property
Pour initialiser la form et l'afficher :
Form1.Chaine1
=
"La première chaîne"
Form1.Chaine2
=
"La deuxième chaîne"
Form1.Show
Ou bien encore :
Form1.Init
"La première chaîne"
, "La deuxième chaîne"
Form1.Show
Nous allons permettre à l'utilisateur de déplacer une form après avoir cliqué dessus, comme s'il avait cliqué dans la barre de titre. Pour cela, nous annulons le clic sur la form et envoyons un clic dans la barre de titre. Commencez par copier ces déclarations au début du module de la form :
Private
Declare
Function
SendMessage Lib
"User32"
Alias "SendMessageA"
_
(
ByVal
hWnd As
Long
, ByVal
wMsg As
Long
, _
ByVal
wParam As
Long
, lParam As
Any) As
Long
Private
Declare
Sub
ReleaseCapture Lib
"User32"
(
)
Const
WM_NCLBUTTONDOWN =
&
HA1
Const
HTCAPTION =
2
Puis le code de la procédure Form_MouseDown() :
Private
Sub
Form_MouseDown
(
Button As
Integer
, Shift As
Integer
, X As
Single
, Y As
Single
)
If
Button =
1
Then
Call
ReleaseCapture
SendMessage Me.hWnd
, WM_NCLBUTTONDOWN, HTCAPTION, 0
&
End
If
End
Sub
Ce code imprime le nom de chaque controle de Form1 dans la fenêtre de débogage:
Dim
Ctrl As
Control
For
Each
Ctrl in
Form1.Controls
Debug.Print
Ctrl.Name
Next
Lien : Comment redimensionner les contrôles quand la form est redimensionnée ?
Cette fonction reçoit en paramètre un objet Control et retourne :
- Vrai si le contrôle appartient à un groupe
- Faux dans le cas contraire
Private
Function
isGroupe
(
C As
Control) As
Boolean
On
Error
Resume
Next
isGroupe =
(
C.Index
>=
0
)
End
Function
L'exemple suivant liste dans la fenêtre d'exécution tous les contrôles d'une form, avec leur nom et index pour ceux qui appartiennent à un groupe :
Private
Sub
Command1_Click
(
)
Dim
C As
Control
For
Each
C In
Form1.Controls
If
isGroupe
(
C) Then
Debug.Print
"Index du controle "
&
C.Name
&
" : "
&
C.Index
Else
Debug.Print
"Le controle "
&
C.Name
&
" n'a pas d'index"
End
If
Next
C
End
Sub
Le module où se trouve le code source d'une form est en fait un module de classe. Un module de classe décrit, comme son nom l'indique, une classe, qui une fois instanciée devient un objet. Donc une form chargée en mémoire pendant l'exécution du programme est en fait une instance de classe.
Si vous avez une form nommée "Form1" dans votre projet, Visual Basic autorise cette syntaxe :
Form1.show
Etonnant, quand on considère que Form1 est le nom d'une classe que l'on peut instancier normalement.
Pour ouvrir plusieurs fois une form, il suffit d'en créer plusieurs instances :
Dim
MaNouvelleForm As
New
Form1
Dim
EncoreUneNouvelleForm As
New
Form1
MaNouvelleForm.Show
EncoreUneNouvelleForm.Show
Les dimensions d'une fenêtre, en nombre de pixels, ne changent pas en fonction de la résolution de l'écran. Donc plus la résolution est importante plus une fenêtre paraît petite à l'écran. C'est le fonctionnement normal d'une interface graphique, mais si vous souhaitez afficher une form ayant proportionnellement toujours la même taille, voici comment procéder.
Affichez la fenêtre de présentation des feuilles (Menu affichage -> présentation des feuilles). Dans cette fenêtre, faites un clic droit et cochez "guides de résolution". Ajustez la taille de la feuille de telle sorte qu"elle ait les proportions souhaitées dans la plus petite résolution supportée par votre application, par exemple 640 x 480 ou bien 800 x 600. L'ajustement de ses dimensions dans les résolutions supérieures est ensuite géré par ce code source, que vous pouvez copier dans le module de la form.
Private
Sub
Form_Load
(
)
'Résolution correspondant à la form telle qu'elle est en mode conception
Const
ResolutionRefX As
Long
=
640
Const
ResolutionRefY As
Long
=
480
'Rapport entre la résolution actuelle et celle de référence
Dim
RatioX As
Single
Dim
RatioY As
Single
'Résolution actuelle
Dim
ResolutionX As
Long
Dim
ResolutionY As
Long
ResolutionX =
Screen.Width
/
Screen.TwipsPerPixelX
ResolutionY =
Screen.Height
/
Screen.TwipsPerPixelY
RatioX =
ResolutionX /
ResolutionRefX
RatioY =
ResolutionY /
ResolutionRefY
'Adapte les dimensions en fonction de la résolution actuelle
ResizeForResolution RatioX, RatioY
End
Sub
Private
Sub
ResizeForResolution
(
ByVal
RatioX As
Single
, ByVal
RatioY As
Single
)
Dim
ctl As
Control
Dim
RatioPolices As
Single
RatioPolices =
(
RatioX +
RatioY) /
2
Me.Width
=
Me.Width
*
RatioX
Me.Height
=
Me.Height
*
RatioY
For
Each
ctl In
Me.Controls
If
TypeOf ctl Is
ComboBox Then
ctl.Move
ctl.Left
*
RatioX, ctl.Top
*
RatioY, ctl.Width
*
RatioX
Else
ctl.Move
ctl.Left
*
RatioX, ctl.Top
*
RatioY, ctl.Width
*
RatioX, ctl.Height
*
RatioY
End
If
If
TypeOf ctl Is
Label Then
ctl.FontSize
=
ctl.FontSize
*
RatioPolices
Next
End
Sub
La procédure ResizeForResolution redimensionne tous les contrôles de la form et agrandit les polices des labels.
En VB, aucun événement ne permet d'être averti lorsqu'une form a été déplacée. Mais pour Windows l'événement existe. Il est donc possible de l'intercepter grâce au sous classement.
Copiez ce code source dans le module de la form.
Private
Sub
Form_Load
(
)
'Remplace la procédure de fenêtre par défaut par notre propre procédure
oldWndProc =
SetWindowLong
(
hwnd, GWL_WNDPROC, AddressOf WindowProc)
End
Sub
Private
Sub
Form_Unload
(
Cancel As
Integer
)
'Remet la procédure de fenêtre par défaut
SetWindowLong hwnd, GWL_WNDPROC, oldWndProc
End
Sub
Et celui-ci dans un module standard.
Public
Declare
Function
SetWindowLong Lib
"user32"
Alias "SetWindowLongA"
_
(
ByVal
hwnd As
Long
, ByVal
nIndex As
Long
, _
ByVal
dwNewLong As
Long
) As
Long
Public
Const
GWL_WNDPROC =
(-
4
)
Public
oldWndProc As
Long
Private
Declare
Function
CallWindowProc Lib
"user32"
Alias "CallWindowProcA"
_
(
ByVal
lpPrevWndFunc As
Long
, ByVal
hwnd As
Long
, _
ByVal
msg As
Long
, ByVal
wParam As
Long
, ByVal
lParam As
Long
) As
Long
Private
Const
WM_MOVE =
&
H3
Public
Function
WindowProc
(
ByVal
hwnd As
Long
, ByVal
msg As
Long
, _
ByVal
wParam As
Long
, ByVal
lParam As
Long
) As
Long
If
msg =
WM_MOVE Then
'la form a été déplacée
Form1.Cls
Form1.Print
"Nouvelle position : "
&
Form1.Left
&
", "
&
Form1.Top
End
If
'Appelle la procédure de fenêtre par défaut pour que Windows puisse traiter l'évènement
WindowProc =
CallWindowProc
(
oldWndProc, hwnd, msg, wParam, lParam)
End
Function
Attention, la procédure Form_Unload doit obligatoirement être exécutée. Si vous déboguez et cliquez sur Stop, l'éditeur VB plantera. Si vous fermez votre programme avec l'instruction End, la procédure Form_Unload ne sera pas exécutée et votre programme plantera.
Ces quelques lignes sont placées dans le module de la MDI mère et ouvrent la MDI fille nommée Form1.
Load Form1
Form1.Left
=
(
Me.ScaleWidth
-
Form1.Width
) /
2
Form1.Top
=
(
Me.ScaleHeight
-
Form1.Height
) /
2
Form1.Show
Fonctionne sous Win 2000 et supérieur. Placez ce code dans un module :
Private
Declare
Function
SetLayeredWindowAttributes Lib
"user32.dll"
(
_
ByVal
hwnd As
Long
, _
ByVal
crKey As
Long
, _
ByVal
bAlpha As
Byte, _
ByVal
dwFlags As
Long
) As
Long
Private
Declare
Function
SetWindowLong Lib
"user32.dll"
Alias "SetWindowLongA"
(
_
ByVal
hwnd As
Long
, _
ByVal
nIndex As
Long
, _
ByVal
dwNewLong As
Long
) As
Long
Private
Const
WS_EX_LAYERED As
Long
=
&
H80000
Private
Const
LWA_ALPHA As
Long
=
&
H2
Private
Const
GWL_EXSTYLE As
Long
=
-
20
Public
Sub
Transparence
(
Forme As
Form, alpha As
Long
)
SetWindowLong Forme.hwnd
, GWL_EXSTYLE, WS_EX_LAYERED
SetLayeredWindowAttributes Forme.hwnd
, 0
, 255
*
alpha /
100
, LWA_ALPHA
End
Sub
Depuis la version de Windows 2000 SP2, les raccourcis clavier, matérialisés par _ ne sont pas visibles sauf lorsque l'on appuie sur ALT justement.
(Une option de configuration est disponible au niveau de Windows.)
Cette astuce permet de restaurer le processus, via le code VB6 :
Private
Declare
Function
SystemParametersInfo Lib
"user32"
Alias "SystemParametersInfoA"
_
(
ByVal
uAction As
Long
, ByVal
uParam As
Long
, ByRef
lpvParam As
Any, ByVal
fuWinIni As
Long
) As
Long
Private
Sub
SetMenuUnderlines
(
ByVal
ShowUnderscore As
Long
, Optional
ByVal
UpdateSystem As
Boolean
=
False
)
Call
SystemParametersInfo
(
SPI_SETMENUUNDERLINES, 0
, ByVal
ShowUnderscore, _
SPIF_SENDWININICHANGE Or
IIf
(
UpdateSystem, SPIF_UPDATEINIFILE, 0
))
End
Sub
Private
Sub
cmdAmpersandOperation_Click
(
)
Const
HIDE_AMPERSAND As
Integer
=
&
H0
Const
SHOW_AMPERSAND As
Integer
=
&
H1
Dim
lngMenusAreUnderlined As
Long
Dim
blnUpdateSystem As
Boolean
Dim
intWhatDoWeDo As
Integer
SystemParametersInfo SPI_GETMENUUNDERLINES, 0
, lngMenusAreUnderlined, 0
If
lngMenusAreUnderlined Then
If
MsgBox
(
"Les légendes de menus dotés d'un & sont affichées..."
&
vbCrLf
&
_
"Voulez-vous les définir comme masquées pour la prochaine session ?"
, vbQuestion
+
vbYesNo
) =
6
Then
intWhatDoWeDo =
HIDE_AMPERSAND
blnUpdateSystem =
MsgBox
(
"Voulez-vous que ce soit pour de bon ?"
, _
vbQuestion
+
vbYesNo
, "Sauver dans le système"
) =
6
Else
intWhatDoWeDo =
SHOW_AMPERSAND
End
If
Else
If
MsgBox
(
"Les légendes de menus dotés d'un & sont masquées..."
&
vbCrLf
&
_
"Voulez-vous les définir comme affichées pour la prochaine session ?"
, vbQuestion
+
vbYesNo
) =
6
Then
intWhatDoWeDo =
SHOW_AMPERSAND
blnUpdateSystem =
MsgBox
(
"Voulez-vous que ce soit pour de bon ?"
, _
vbQuestion
+
vbYesNo
, "Sauver dans le système"
) =
6
Else
intWhatDoWeDo =
HIDE_AMPERSAND
End
If
End
If
SetMenuUnderlines intWhatDoWeDo, blnUpdateSystem
Unload Me
End
End
Sub