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
Sommaire→Interface→Form- 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
NextVous pouvez ensuite les détruire :
Dim i As Long
For i = 1 To 9
Unload Text1(i)
NextUne 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.TextBoxNous 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 = TruePour supprimer le contrôle :
Me.Controls.Remove "txtDynamic"
Set TextBoxDynamique = NothingQuand 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 SubPlacez 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 LongPuis 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 LongPour 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 SubPour 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 SubAjoutez 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 LongEt placez cette ligne dans la procédure Form_Load :
SetWindowPos Me.hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZEPour annuler, placez cette ligne dans la procédure adéquate :
SetWindowPos Me.hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZEPour 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 SubDans 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 SubPour 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 SubElles sont dans la collection Forms. Ainsi cette boucle décharge toutes les forms :
Dim f As Form
For Each f In Forms
Unload f
NextPlacez 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 SubLien : 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 PropertyPour initialiser la form et l'afficher :
Form1.Chaine1 = "La première chaîne"
Form1.Chaine2 = "La deuxième chaîne"
Form1.ShowOu bien encore :
Form1.Init "La première chaîne", "La deuxième chaîne"
Form1.ShowNous 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 = 2Puis 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 SubCe 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
NextLien : 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 FunctionL'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 SubLe 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.showEtonnant, 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.ShowLes 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 SubLa 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 SubEt 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 FunctionAttention, 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.ShowFonctionne 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


