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 choisir entre une MSFlexgrid et une Datagrid ?
- Comment permettre à l'utilisateur de taper du texte dans une flexgrid ?
- Comment avoir une case à cocher dans une flexgrid (2 méthodes)?
- Comment n'autoriser la sélection que d'une seule ligne dans une MSFlexgrid ?
- Comment exporter le contenu d'une msflexgrid dans un fichier ?
- Comment modifier la largeur des colonnes d'une MSFlexgrid en fonction de la longueur du texte ?
- Comment adapter les dimensions d'une image à celle d'un PictureBox ?
- Comment contrôler les caractères qui peuvent être saisis dans un textbox ?
- Comment annuler la dernière modification du contenu d'un textbox (undo) ?
- Comment récupérer une par une les lignes d'un textbox multilignes ?
- Comment afficher son propre menu popup dans un textbox ?
- Comment utilise-t-on le contrôle TabStrip ?
- Comment se connecter à une base Access 2000 avec un contrôle Data ?
- Comment imprimer le contenu d'un RichTextBox ?
- Comment concaténer le contenu de deux contrôles RTF ?
- Comment mettre plusieurs colonnes dans une ComboBox ?
- Comment dérouler une ComboBox ?
- Comment modifier la largeur de la zone de déroulement d'une ComboBox ?
- Comment modifier la hauteur de la zone de déroulement d'une ComboBox ?
- Comment ajouter une fonctionnalité de correspondance à une ComboBox ?
- Comment ajouter un ascenseur horizontal à une ListBox ?
- Comment aligner des entrées multicolonnes dans une ListBox ?
- Comment lier une DataCombo ou une DataList à un champ d'une base de données ?
- Comment tester l'existence d'un noeud dans un contrôle TreeView ?
- Comment définir la couleur d'arrière-plan d'un TreeView ?
- Comment donner un effet d'ombre à un contrôle ?
- Comment savoir s'il y a une image dans un contrôle ?
- Comment savoir si une propriété existe pour un contrôle ?
- Comment dérouler un bouton DropDown dans une ToolBar en cliquant sur l'ensemble du bouton ?
- Comment donner le style de Windows XP à mes contrôles VB6 ?
- Comment faire évoluer un ProgressBar en fonction d'un FileCopy?
- Utilise le contrôle Common Dialog pour récupérer le chemin d'un fichier
- Comment sélectionner plusieurs extensions dans le filtre d'un CommonDialog ?
- Comment copier une image dans un RichTextBox ?
- Comment faire de l'auto complétion avec une Combobox standard ?
La datagrid est réservée à l'utilisation d'une grille liée à une source de données. Vous pouvez modifier le format d'affichage de chaque colonne. L'utilisateur peut saisir les valeurs au clavier, ajouter et supprimer des lignes. Toutes ces modifications sont prises en compte dans la base de données, avec très peu voire aucune programmation. Cependant, les choses se compliquent très vite dès que vous voulez modifier des données portant sur plusieurs tables de la base.
Quant à la MSFlexgrid, son inconvénient majeur est la non prise en charge de saisie de données. Il reste cependant plusieurs façons de combler ce manque avec quelques lignes de code. Elle peut être liée à une source de données comme la datagrid, mais le format d'affichage n'est pas modifiable. Vous pouvez aussi remplir la grille par programmation, ligne par ligne, ce qui vous permet d'afficher exactement ce que vous voulez; par contre cela peut être moins rapide à l'exécution sur un très grand nombre de lignes. A cela, il faut ajouter les possibilités de modifier la police, la couleur du texte, la couleur de fond d'une cellule, d'afficher une image dans une cellule, et de fusionner plusieurs cellules adjacentes qui contiennent la même valeur. La MSFlexgrid est donc à mon avis préférable dans la plupart des cas.
Ce programme ajoute dans la cellule courante les caractères au fur et à mesure qu'ils sont tapés. Une autre manière de faire consiste à placer un textbox qui recouvre la cellule courante, et de transférer le texte du textbox dans la cellule chaque fois que l'on quitte le textbox (évènement lostfocus).
Dim
strTexte
strTexte =
MSFlexGrid1.Text
If
KeyAscii =
8
Then
'Touche d'effacement
If
Len
(
strTexte) >
0
Then
MSFlexGrid1.Text
=
Left
(
strTexte, Len
(
strTexte) -
1
)
ElseIf
KeyAscii <>
13
Then
MSFlexGrid1.Text
=
strTexte &
Chr
(
KeyAscii)
End
If
La méthode la plus simple consiste à utiliser des images représentant chacune un des états possibles de la case à cocher.
Ici nous aurons deux images: une pour représenter une case non cochée et une autre pour la case cochée. Ces images sont stockées dans
deux simples contrôles images.
Dans toutes les cellules qui doivent contenir une case à cocher, nous insérons l'image correspondant à l'état courant de la case à cocher.
Les deux procédures du code source ci-dessous montrent comment afficher la case à cocher. La procédure InitCelluleAvecCase() initialise une cellule pour qu'elle puisse contenir une case à cocher. Elle appelle la procédure AfficheCelluleAvecCase() qui elle se contente d'afficher la bonne image.
Private
Sub
InitCelluleAvecCase
(
ligne As
Long
, colonne As
Long
, Optional
valeur As
Boolean
=
False
)
MSFlexGrid1.Col
=
colonne
MSFlexGrid1.Row
=
ligne
MSFlexGrid1.CellPictureAlignment
=
flexAlignCenterCenter
AfficheCelluleAvecCase ligne, colonne, valeur
End
Sub
Private
Sub
AfficheCelluleAvecCase
(
ligne As
Long
, colonne As
Long
, Optional
valeur As
Boolean
=
False
)
Set
MSFlexGrid1.CellPicture
=
IIf
(
valeur, imgCaseCochee.Picture
, imgCase.Picture
)
End
Sub
Voici un exemple complet qui utilise nos deux procédures. Au chargement de la form, la msflexgrid est initialisée pour afficher un tableau de commandes. Dans la troisième colonne de la grille, une case à cocher indique si la commande a été envoyée.
Private
Type
commande
reference As
String
montant As
Single
envoyee As
Boolean
End
Type
Dim
commandes
(
0
To
2
) As
commande
Private
Sub
Form_Load
(
)
Dim
i As
Long
'tableau de commandes
commandes
(
0
).reference
=
"cmd0001"
: commandes
(
0
).montant
=
80
: commandes
(
0
).envoyee
=
True
commandes
(
1
).reference
=
"cmd0002"
: commandes
(
1
).montant
=
150
.2
: commandes
(
1
).envoyee
=
False
commandes
(
2
).reference
=
"cmd0003"
: commandes
(
2
).montant
=
95
.5
: commandes
(
2
).envoyee
=
True
'initialisation de la msflexgrid
MSFlexGrid1.Cols
=
3
MSFlexGrid1.Rows
=
4
MSFlexGrid1.FixedCols
=
0
For
i =
0
To
2
MSFlexGrid1.TextMatrix
(
i +
1
, 0
) =
commandes
(
i).reference
MSFlexGrid1.TextMatrix
(
i +
1
, 1
) =
commandes
(
i).montant
InitCelluleAvecCase i +
1
, 2
, commandes
(
i).envoyee
Next
End
Sub
Private
Sub
MSFlexGrid1_Click
(
)
If
MSFlexGrid1.Col
=
2
And
MSFlexGrid1.MouseRow
>
0
Then
commandes
(
MSFlexGrid1.Row
-
1
).envoyee
=
Not
commandes
(
MSFlexGrid1.Row
-
1
).envoyee
AfficheCelluleAvecCase MSFlexGrid1.Row
, 2
, commandes
(
MSFlexGrid1.Row
-
1
).envoyee
End
If
End
Sub
Méthode testée sous Win XP :
Private
Const
Checked As
Byte =
253
Private
Const
UnChecked As
Byte =
168
Private
Sub
Form_Load
(
)
Dim
CCol, CRow As
Integer
With
MSFlexGrid1
.FixedCols
=
0
.FixedRows
=
1
.Cols
=
8
.Rows
=
8
.ColAlignment
(
2
) =
flexAlignCenterCenter
For
CRow =
.FixedRows
To
.Rows
-
1
For
CCol =
0
To
.Cols
-
1
.TextMatrix
(
CRow, CCol) =
"Cel "
&
CRow &
", "
&
CCol
Next
CCol
.Col
=
2
.Row
=
CRow
.CellFontName
=
"Wingdings"
.CellFontSize
=
12
.CellFontBold
=
False
.Text
=
Chr
(
UnChecked)
Next
CRow
End
With
End
Sub
Private
Sub
MSFlexGrid1_Click
(
)
With
MSFlexGrid1
If
.Col
=
2
Then
If
.Text
=
Chr
(
UnChecked) Then
.Text
=
Chr
(
Checked)
ElseIf
.Text
=
Chr
(
Checked) Then
.Text
=
Chr
(
UnChecked)
End
If
End
If
End
With
End
Sub
Il n'existe pas de propriété pour le faire mais voici une astuce possible :
Private
Sub
MSFlexGrid1_SelChange
(
)
MSFlexGrid1.RowSel
=
MSFlexGrid1.Row
End
Sub
Si vous essayez de sélectionner plusieurs lignes à la souris, vous verrez un clignotement que vous pouvez éviter en empêchant le rafraîchissement automatique de la grille tant que le bouton de la souris est enfoncé :
Private
Sub
MSFlexGrid1_MouseDown
(
Button As
Integer
, Shift As
Integer
, x As
Single
, y As
Single
)
MSFlexGrid1.Redraw
=
False
End
Sub
Private
Sub
MSFlexGrid1_MouseUp
(
Button As
Integer
, Shift As
Integer
, x As
Single
, y As
Single
)
MSFlexGrid1.Redraw
=
True
End
Sub
Cette fonction exporte le contenu de la msflexgrid passée en paramètre dans le fichier strFileName. Les colonnes sont séparées par le caractère passé dans le troisième paramètre.
Public
Function
ExportGridToFile
(
Mygrid As
MSFlexGrid, Byval
strFileName as
string
, _
Optional
ByVal
strSep As
String
=
vbTab
) As
Boolean
Dim
intFreeFile As
Integer
'Numéro du fichier
Dim
intCol As
Integer
, intRow As
Integer
'Indices de ligne et colonne de W
Dim
ligne As
String
'La ligne à écrire dans le fichier
On
Error
GoTo
ExportGridToFile_ERR
'Prend le prochain numéro de fichier
intFreeFile =
FreeFile
'Ouvre le fichier en bloquant son accès aux autres applications
Open strFileName For
Output Access Write Lock Read Write As
#intFreeFile
With
Mygrid
'Pour chaque ligne
For
intRow =
.FixedRows
To
.Rows
-
1
ligne =
""
'Pour chaque colonne
For
intCol =
.FixedCols
To
.Cols
-
1
'Ajoute la valeur de la cellule
ligne =
ligne &
.TextMatrix
(
intRow, intCol) &
strSep
Next
intCol
'Enlève le séparateur final
If
strSep <>
""
Then
ligne =
Left
(
ligne, Len
(
ligne) -
1
)
Print #intFreeFile, ligne
Next
intRow
End
With
'Valide le bon fonctionnement de la fonction
ExportGridToFile =
True
ExportGridToFile_FIN
:
Close #intFreeFile +
1
Exit
Function
ExportGridToFile_ERR
:
ExportGridToFile =
False
Resume
ExportGridToFile_FIN
End
Function
Copiez ce code dans un module standard :
Private
Type
Size
cx As
Long
cy As
Long
End
Type
Private
Declare
Function
GetTextExtentPoint32 Lib
"gdi32"
Alias "GetTextExtentPoint32A"
_
(
ByVal
hdc As
Long
, ByVal
lpsz As
String
, _
ByVal
cbString As
Long
, lpSize As
Size) As
Long
Public
Sub
ResizeColumns
(
hdc As
Long
, flexgrid As
MSFlexGrid)
Dim
idxRow As
Long
, idxCol As
Long
, lngMax As
Long
Dim
texte As
String
, taille As
Size
With
flexgrid
'Parcoure les colonnes
For
idxCol =
0
To
.Cols
-
1
lngMax =
0
'Parcoure les lignes
For
idxRow =
0
To
.Rows
-
1
texte =
.TextMatrix
(
idxRow, idxCol)
'met la taille du texte de la cellule en pixels dans taille
GetTextExtentPoint32 hdc, texte, Len
(
texte), taille
'lngMax est la longueur du texte le plus long dans cette colonne
If
taille.cx
>
lngMax Then
lngMax =
taille.cx
Next
'met lngMax en twips en ajoutant 10 pixels pour les marges
If
lngMax >
0
Then
lngMax =
(
lngMax +
10
) *
Screen.TwipsPerPixelX
'Applique la largeur de colonne si besoin
If
lngMax >
.ColWidth
(
idxCol) Then
.ColWidth
(
idxCol) =
lngMax
Next
End
With
End
Sub
Voici comment appeler la procédure ResizeColumns :
ResizeColumns Me.hdc
, MSFlexGrid1
La procédure attend un contexte de périphérique en premier paramètre. Le contexte de périphérique est renvoyé par la propriété hdc. Si la form et la MSFlexGrid ont la même police, vous pouvez passer le contexte de périphérique de la form. Sinon vous pouvez ajouter un PictureBox invisible qui aura la même police que celle de la MSFlexgrid et passer sa propriété hdc en premier paramètre.
Picture1.PaintPicture
Image1.Picture
, 0
, 0
, Picture1.Width
, Picture1.Height
Une solution consiste à utiliser l'évènement KeyPress, qui a lieu lorsqu'une touche correspondant à un caractère est enfoncée. Les touches comme shift, alt, control et F1 à F12 ne sont pas concernées. La procédure de cet évènement a un argument, KeyAscii, qui est le code du caractère à afficher. Modifiez sa valeur pour afficher le caractère que vous voulez. Donnez-lui une valeur nulle si aucun caractère ne doit être affiché. La fonction chr() renvoie le caractère dont le code est passé en paramètre.
L'exemple suivant interdit tout caractère autre que les chiffres et la touche d'effacement :
Private
Sub
Text1_KeyPress
(
KeyAscii As
Integer
)
If
KeyAscii <>
8
Then
If
Not
IsNumeric
(
Chr
(
KeyAscii)) Then
KeyAscii =
0
End
If
End
Sub
Une astuce souvent utilisée consiste à rechercher le caractère entré, dans une chaîne contenant tous les caractères autorisés. Si ce caractère n'est pas dans la chaîne, rien n'est affiché :
Private
Sub
Text1_KeyPress
(
KeyAscii As
Integer
)
Dim
allowedKeys As
String
allowedKeys =
"0123456789-,."
&
Chr
(
8
)
If
InStr
(
allowedKeys, Chr
(
KeyAscii)) =
0
Then
KeyAscii =
0
End
Sub
Une solution possible est de simuler l'appui sur les touches ctrl + z :
Text1.SetFocus
SendKeys "^z"
Mais vous pouvez aussi envoyer le message EM_UNDO au textbox, grâce à la fonction SendMessage() de l'Api Windows. Ajoutez tout d'abord ces déclarations :
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
Const
EM_UNDO =
&
HC7
Pour annuler la dernière modification sur le contenu de Text1 :
SendMessage Text1.hwnd
, EM_UNDO, 0
, 0
Une première idée serait d'utiliser la fonction Split() avec vbCrLf comme séparateur. Mais une fin de ligne n'est pas forcément due à un retour chariot. Nous allons plutôt faire appel aux API Windows.
Copiez tout d'abord 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
CopyMemory Lib
"kernel32"
Alias "RtlMoveMemory"
(
Destination As
Any, Source As
Any, _
ByVal
Length As
Long
)
Private
Const
EM_GETLINECOUNT =
&
HBA
Private
Const
EM_LINELENGTH =
&
HC1
Private
Const
EM_LINEINDEX =
&
HBB
Private
Const
EM_GETLINE =
&
HC4
La procédure ci-dessous affiche une par une les lignes du textbox dont le handle est passé en paramètre :
Private
Sub
AfficheLignes
(
lngHandleTextBox As
Long
)
Dim
lngNbLignes As
Long
, i As
Long
Dim
lngIndexCar As
Long
, intLongueurLigne As
Integer
Dim
strLigne As
String
'nombre de lignes
lngNbLignes =
SendMessage
(
lngHandleTextBox, EM_GETLINECOUNT, 0
, 0
)
For
i =
1
To
lngNbLignes
'index du premier caractère de la ligne
lngIndexCar =
SendMessage
(
lngHandleTextBox, EM_LINEINDEX, i -
1
, 0
)
'longueur de la ligne
intLongueurLigne =
SendMessage
(
lngHandleTextBox, EM_LINELENGTH, lngIndexCar, 0
)
'récupère la ligne dans la chaîne strLigne
strLigne =
Space
(
intLongueurLigne)
CopyMemory ByVal
strLigne, intLongueurLigne, Len
(
intLongueurLigne)
SendMessage lngHandleTextBox, EM_GETLINE, i -
1
, ByVal
strLigne
MsgBox
strLigne
Next
End
Sub
Créez un menu dans la form et rendez-le invisible. Puis créez des sous-menus visibles. Ce sont ces derniers qui apparaîtront dans le menu popup.
Tout se passe dans la procédure MouseDown. Afin d'empêcher le menu contextuel de Windows de s'afficher lorsque l'utilisateur va relâcher la souris, nous désactivons le textbox puis le réactivons immédiatement.
Private
Sub
Text1_MouseDown
(
Button As
Integer
, Shift As
Integer
, X As
Single
, Y As
Single
)
If
Button =
vbRightButton Then
Text1.Enabled
=
False
Text1.Enabled
=
True
PopupMenu menuTextBox 'menuTextBox est le nom du menu invisible
End
If
End
Sub
Le contrôle TabStrip représente un ensemble d'onglets. Mais il ne permet pas d'associer des contrôles (textbox, commandbutton, etc...) à chacun des onglets. Vous devez donc gérer vous même l'affichage des contrôles en fonction de l'onglet qui est actif. Le plus simple est d'utiliser des frames indexées, et de mettre au premier plan la frame correspondant à l'onglet activé. Ici la première frame est d'index 1 :
Private
Sub
TabStrip1_Click
(
)
frameOnglet
(
TabStrip1.SelectedItem.Index
).ZOrder
0
End
Sub
Toutefois, on utilise plus souvent le contrôle Tabstrip lorsque plusieurs onglets utilisent une même frame. Dans ce cas on met dans la propriété tag de chaque objet Tab l'index de la frame qu'il doit mettre au premier plan. Le code devient alors :
Private
Sub
TabStrip1_Click
(
)
frameOnglet
(
TabStrip1.SelectedItem.Tag
).ZOrder
0
End
Sub
Il n'est pas la peine d'aligner ni de dimensionner les Frames de votre TabStrip. En général on utilise un code d'alignement dans l'événement Load de la feuille semblable à celui-ci :
For
compteur =
0
To
frameOnglet.Count
-
1
With
TabStrip1
frameOnglet
(
compteur).Move
.ClientLeft
, .ClientTop
, .ClientWidth
, .ClientHeight
End
With
Next
compteur
Pour cela, DAO 3.6 et Jet 4.0 doivent être installés. Dans les références de votre projet, enlevez "Microsoft DAO 3.5 Object Library" et sélectionnez "Microsoft DAO 3.6 Object Library". Puis utilisez ce code source pour vous connecter :
Dim
daoDB36 As
Database
Dim
rs As
Recordset
Dim
sPath As
String
sPath =
"c:\base.mdb"
Set
daoDB36 =
DBEngine.OpenDatabase
(
sPath)
Set
rs =
daoDB36.OpenRecordset
(
"tClients"
)
Set
Data1.Recordset
=
rs
Un code source vous permettant d'imprimer un RichTextBox, avec la gestion des pages, est dans cet article de MSDN.
Sur une feuille, placez 2 contrôles RichTextBox avec leur texte respectif et un bouton de commande Command1. Placez ensuite ce code dans le module de la form.
Private
Function
ConcatRTF
(
RTF1 As
String
, RTF2 As
String
) As
String
ConcatRTF =
Left
(
RTF1, InStrRev
(
RTF1, "}"
) -
1
) &
Mid
(
RTF2, 2
)
End
Function
Private
Sub
Command1_Click
(
)
With
Me.RichTextBox1
.TextRTF
=
ConcatRTF
(
.TextRTF
, Me.RichTextBox2.TextRTF
)
.Refresh
End
With
End
Sub
Ce n'est pas possible avec la ComboBox standard. Par contre, celle incluse dans le composant Microsoft Forms 2.0 dispose de cette fonctionnalité.
- Ajoutez le composant Microsoft Forms 2.0 Object Library dans votre projet. Cela a pour effet d'ajouter des contrôles dans la boîte à outils, dont le contrôle ComboBox (il a le même nom que la ComboBox standard de VB mais il est plus évolué).
- Ajoutez un nouveau contrôle ComboBox sur votre Form.
- Modifiez sa propriété ColumnCount à la valeur souhaitée.
L'exemple suivant montre comment remplir une ComboBox à 3 colonnes :
Dim
i As
Integer
For
i =
0
To
4
cboTest.AddItem
cboTest.List
(
i, 0
) =
"Lig "
&
i &
" Col 0"
cboTest.List
(
i, 1
) =
"Lig "
&
i &
" Col 1"
cboTest.List
(
i, 2
) =
"Lig "
&
i &
" Col 2"
Next
i
Pour qu'une colonne soit cachée, il suffit de mettre sa largeur à 0. Par exemple pour qu'une ComboBox ait 3 colonnes et que les deux premières soient cachées :
Combo1.ColumnCount
=
3
Combo1.ColumnWidths
=
"0"
&
";"
&
"0"
&
";"
&
"3975"
Habituellement, une ComboBox se déroule quand l'utilisateur clique dessus. Si vous voulez la dérouler avec du code, placez ces déclarations dans un module :
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
Const
CB_SHOWDROPDOWN =
&
H14F
Public
Sub
DerouleCombo
(
handle As
Long
)
SendMessage handle, CB_SHOWDROPDOWN, True
, ByVal
0
End
Sub
Voici comment par exemple dérouler automatiquement une combo quand elle reçoit le focus :
Private
Sub
Combo1_GotFocus
(
)
DerouleCombo Combo1.hwnd
End
Sub
Copiez ce code dans un module standard :
Private
Const
CB_GETLBTEXTLEN =
&
H149
Private
Const
CB_SHOWDROPDOWN =
&
H14F
Private
Const
CB_GETDROPPEDWIDTH =
&
H15F
Private
Const
CB_SETDROPPEDWIDTH =
&
H160
Private
Const
CB_MSGMAX =
&
H15B
Private
Const
CB_SETITEMHEIGHT =
&
H153
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
Public
Sub
LargeurCombo
(
hwnd As
Long
, largeur As
Long
)
SendMessage hwnd, CB_SETDROPPEDWIDTH, largeur, ByVal
0
End
Sub
La procédure LargeurCombo modifie la largeur de la zone de déroulement de la combo dont le handle est passé en paramètre. Pour la tester, posez une combo sur une form et placez code dans le module de la form :
Private
Sub
Form_Load
(
)
Dim
i As
Long
For
i =
1
To
20
Combo1.AddItem
"ligne "
&
i
Next
LargeurCombo Combo1.hwnd
, 300
End
Sub
Ceci est possible en faisant appel à l'api MoveWindow. Copiez ce code dans module standard.
Private
Declare
Function
MoveWindow Lib
"user32"
(
ByVal
hwnd As
Long
, _
ByVal
x As
Long
, ByVal
y As
Long
, _
ByVal
nWidth As
Long
, ByVal
nHeight As
Long
, _
ByVal
bRepaint As
Long
) As
Long
Public
Sub
SetCtrlHeight
(
vCtrl As
Control, vHeight As
Long
)
Dim
xForm As
VB.Form
, xCont As
Object, XScaleMode As
ScaleModeConstants
'Trouve où est situé le contrôle (Formulaire et Contenant)
Set
xForm =
vCtrl.Parent
Set
xCont =
vCtrl.Container
'Enlève le contrôle de son contenant pour le mettre sur la form
Set
vCtrl.Container
=
xForm
'Sauvegarde ScaleMode avant de le modifier
XScaleMode =
xForm.ScaleMode
'Met ScaleMode du formulaire en Pixels car MoveWindow utilise les pixels
xForm.ScaleMode
=
vbPixels
'Redimentionne la fenêtre du ComboBox
MoveWindow vCtrl.hwnd
, vCtrl.Left
, vCtrl.Top
, vCtrl.Width
, vHeight, 1
'Remet ScaleMode à sa valeur initiale
xForm.ScaleMode
=
XScaleMode
'Remet le contrôle dans son contenant initial
Set
vCtrl.Container
=
xCont
End
Sub
Voici comment donner à la zone de déroulement d'une combo box une hauteur de 180 pixels :
Private
Sub
Form_Load
(
)
Dim
xHeight As
Long
xHeight =
180
' en pixel : affiche 12 lignes en Font MS sans Serif taille 8
Call
SetCtrlHeight
(
Combo1, xHeight)
End
Sub
Cette fonctionnalité consiste à sélectionner automatiquement l'élément de la liste dont le début correspond aux caractères saisis dans la combo. Si aucun n'élément ne correspond, rien n'est sélectionné.
Copiez tout d'abord 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
Const
CB_FINDSTRING =
&
H14C
Tout le reste du code se situe dans la procédure de l'événement KeyPress, qui a lieu chaque fois qu'un caractère est entré :
Private
Sub
Combo1_KeyPress
(
KeyAscii As
Integer
)
Dim
Trouve As
Long
, Position As
Integer
, Taille As
Integer
, strTemp As
String
With
Me.Combo1
If
KeyAscii =
8
Then
If
.SelStart
=
0
Then
Exit
Sub
.SelStart
=
.SelStart
-
1
.SelText
=
""
Else
Position =
.SelStart
strTemp =
.Text
End
If
.SelText
=
Chr
(
KeyAscii)
Trouve =
SendMessage
(
.hwnd
, CB_FINDSTRING, 0
, ByVal
.Text
)
If
Trouve =
-
1
Then
'les trois lignes suivantes doivent être enlevées en cas de non correspondance possible
.Text
=
strTemp
.SelStart
=
Position
.SelLength
=
(
Len
(
.Text
) -
Position)
KeyAscii =
0
Exit
Sub
Else
Position =
.SelStart
Taille =
Len
(
.List
(
Trouve)) -
Len
(
.Text
)
.SelText
=
.SelText
&
Right
(
.List
(
Trouve), Taille)
.SelStart
=
Position
.SelLength
=
Taille
KeyAscii =
0
End
If
End
With
End
Sub
Si l'un des éléments d'une ListBox est trop long pour pouvoir être affiché entièrement dans la liste, un ascenseur horizontal serait bien utile, mais ce contrôle n'a pas de propriété permettant de l'indiquer. Afin qu'un ascenseur soit créé quand l'un des éléments dépasse la largeur de la liste, copiez tout d'abord ce code dans un module.
Private
Declare
Function
DrawText Lib
"user32"
Alias "DrawTextA"
(
ByVal
hdc As
Long
, ByVal
lpStr As
String
, _
ByVal
nCount As
Long
, lpRect As
RECT, _
ByVal
wFormat As
Long
) As
Long
Private
Declare
Function
GetSystemMetrics Lib
"user32"
(
ByVal
nIndex As
Long
) As
Long
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
Const
LB_SETHORIZONTALEXTENT =
&
H194
Private
Const
DT_CALCRECT =
&
H400
Private
Const
SM_CXVSCROLL =
2
Private
Type
RECT
Left
As
Long
Top As
Long
Right
As
Long
Bottom As
Long
End
Type
Public
Sub
ApplyScrollBar
(
ByVal
hdc As
Long
, MaListe As
ListBox)
Dim
compteur As
Long
, Nlargeur As
Long
, LargText As
Long
, sysScrollWidth As
Long
Dim
rcText As
RECT
sysScrollWidth =
GetSystemMetrics
(
SM_CXVSCROLL)
For
compteur =
0
To
MaListe.ListCount
-
1
DrawText hdc, MaListe.List
(
compteur), -
1
&
, rcText, DT_CALCRECT
LargText =
rcText.Right
+
sysScrollWidth
If
LargText >=
Nlargeur Then
Nlargeur =
LargText
End
If
Next
compteur
SendMessage MaListe.hwnd
, LB_SETHORIZONTALEXTENT, Nlargeur, ByVal
0
&
End
Sub
Ensuite, appelez la procédure ApplyScrollBar chaque fois que vous ajoutez ou supprimez un élément dans la liste, ce qui aura pour effet d'afficher ou de supprimer l'ascenseur et d'actualiser sa taille s'il reste visible. Pour tester ce code, placez une listbox sur une form et placez ce code dans le module de la form :
Private
Sub
Form_Load
(
)
List1.AddItem
"fjkzlqgj fjekljdsk"
List1.AddItem
"fjkzlqgj fjekd jfskdlqgjslkdgjklsq fjdsk"
List1.AddItem
"fjkzlqgj fjekl"
ApplyScrollBar Me.hdc
, List1
End
Sub
Si vous préférez ne pas utiliser la collection Microsoft Forms 2.0, il existe néanmoins une manière propre de présenter une entrée multicolonnes dans une ListBox:
Les items doivent être insérés dans la liste séparés par des tabulations, par exemple:
List1.Additem
"champ1"
&
vbTab
&
"champ2"
&
vbTab
&
"champ3"
Si la police est à chasse fixe (Courrier, par exemple), les colonnes sont alors correctement alignées, mais si la police est à chasse variable (ce qui est le cas la plupart du temps), il faut utiliser les API de Windows pour faire un alignement correct, comme suit:
Placez ce code dans un module:
Public
Declare
Function
SendMessage Lib
"user32"
Alias "SendMessageA"
_
(
ByVal
hwnd As
Long
, ByVal
wMsg As
Long
, _
ByVal
wParam As
Long
, lParam As
Any) As
Long
Public
Const
LB_SETTABSTOPS =
&
H192
Utilisez ensuite le code suivant pour produire une liste avec des champs alignés proprement:
Private
Sub
Form_Load
(
)
'ce tableau va contenir les positions des tabulations (ce qui equivaut
'à la largeur des colonnes
ReDim
tabstop
(
0
To
2
) As
Long
'on positionne les tabulations
tabstop
(
0
) =
90
tabstop
(
1
) =
130
tabstop
(
2
) =
185
'on efface puis on réinitialise les tabulations
Call
SendMessage
(
List1.hwnd
, LB_SETTABSTOPS, 0
&
, ByVal
0
&
)
Call
SendMessage
(
List1.hwnd
, LB_SETTABSTOPS, 3
, tabstop
(
0
))
List1.Refresh
End
Sub
Nous allons voir comment placer dans une combo ou une liste les valeurs contenues dans un champ d'une base de données en vue d'une sélection d'un enregistrement. La liaison directe avec la source de données évite la boucle de lecture du recordset ainsi que l'instruction additem et facilite la lecture des autres champs de l'enregistrement sélectionné.
Placez un contrôle DataCombo ou DataList sur une feuille et initialisez une connexion à une base de données; ensuite, insérez ce code :
Set
DataCombo1.DataSource
=
rst
Set
DataCombo1.RowSource
=
rst
DataCombo1.ListField
=
"MonChamp"
'nom du champ
Si l'on désire voir l'élément sélectionné en surbrillance, il faut ajouter au code précédent :
DataCombo1.DataField
=
"MonChamp"
Pour placer le recordset sur l'élément sélectionné et récupérer la valeur des autres champs de cet enregistrement :
Private
Sub
DataCombo1_Click
(
)
If
DataCombo1 <>
""
Then
rst.Bookmark
=
DataCombo1.SelectedItem
End
If
Text1.Text
=
rst.Fields
(
"AutreChamp"
) ' nom d'un champ quelconque dans la base
End
Sub
Chaque noeud d'un TreeView possède une clé qui est un identifiant unique, assigné au moment de l'insertion et dont on se sert ici afin de tester l'existence d'un noeud:
If
Treeview.Nodes
(
cle_a_verifier) Is
Nothing
Then
'le noeud n'existe pas
End
If
Contrairement à une opinion largement répandue, il est possible de changer la couleur d'arrière-plan d'un TreeView.
Placez ces déclarations dans un module :
Private
Const
GWL_STYLE As
Long
=
(-
16
)
Private
Const
TVS_HASLINES As
Long
=
2
Private
Const
TV_FIRST As
Long
=
&
H1100
Private
Const
TVM_SETBKCOLOR As
Long
=
(
TV_FIRST +
29
)
Private
Const
TVM_SETTEXTCOLOR As
Long
=
(
TV_FIRST +
30
)
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
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
Ensuite, placez la procédure suivante dans la section générale du formulaire:
Public
Sub
SetTreeViewArrPlan
(
ByVal
treeview As
MSComctlLib.treeview
, ByVal
couleur As
Long
)
Dim
style As
Long
, noeud As
Node
'Changement de l'arrière-plan du treeview
Call
SendMessage
(
treeview.hwnd
, TVM_SETBKCOLOR, 0
, ByVal
couleur)
'réinitialisation de l'arbre
style =
GetWindowLong
(
treeview.hwnd
, GWL_STYLE)
'Si l'arbre a des lignes, on les désactive temporairement pour que
'l'arrière-plan se redessine proprement, puis on les réactive
If
style And
TVS_HASLINES Then
SetWindowLong treeview.hwnd
, GWL_STYLE, style Xor
TVS_HASLINES
SetWindowLong treeview.hwnd
, GWL_STYLE, style
End
If
'on change la couleur de fond des noeuds
For
Each
noeud In
treeview.Nodes
noeud.BackColor
=
couleur
Next
End
Sub
L'appel se fait comme suit :
Dim
couleur As
Long
couleur =
vbRed
SetTreeViewArrPlan TreeView1, couleur
Dans un module standard, placez ce code :
Public
Const
RELIEF =
1
Public
Const
ENCADREMENT =
2
Public
Sub
Ombrage
(
Feuille As
Form, Ctrl As
Control, Effet As
Integer
, OmbreLarg As
Integer
, OmbreCoul As
Long
)
Dim
CouleurOmbre As
Long
Dim
LargeurOmbre As
Integer
Dim
Largeur As
Integer
Dim
Taille As
Integer
LargeurOmbre =
OmbreLarg
CouleurOmbre =
OmbreCoul
Largeur =
Feuille.DrawWidth
Taille =
Feuille.ScaleMode
Feuille.DrawWidth
=
1
Select
Case
Effet
Case
ENCADREMENT
Feuille.Line
(
Ctrl.Left
+
LargeurOmbre, Ctrl.Top
+
LargeurOmbre)-
_
Step
(
Ctrl.Width
-
1
, Ctrl.Height
-
1
), CouleurOmbre, BF
Case
RELIEF
Feuille.Line
(
Ctrl.Left
-
LargeurOmbre, Ctrl.Top
-
LargeurOmbre)-
_
Step
(
Ctrl.Width
-
1
, Ctrl.Height
-
1
), CouleurOmbre, BF
End
Select
Feuille.DrawWidth
=
Largeur
Feuille.ScaleMode
=
Taille
End
Sub
Posez, par exemple, un PictureBox sur votre feuille, et placez ce code dans le module de la feuille :
Private
Sub
Form_Paint
(
)
Ombrage Me, Picture1, ENCADREMENT, 10
, QBColor
(
5
) 'contour du cadre accentué
Ombrage Me, Picture1, RELIEF, 10
, QBColor
(
5
) 'effet d'enfoncement de l'image
End
Sub
La fonction ci-dessous renvoie Vrai si le contrôle passé en paramètre contient une image.
Public
Function
ImagePresente
(
controle As
Control) As
Boolean
ImagePresente =
(
controle.Picture.Handle
>
0
)
End
Function
Il peut être utile de savoir si une propriété existe pour un contrôle donné, dans une boucle par exemple, afin d'éviter les erreurs
Insérez ce code dans la section déclaration de votre form ou dans un module :
Public
Function
ExistProperty
(
Obj As
Object, ByVal
PropertyName As
String
) As
Boolean
On
Error
Resume
Next
CallByName Obj, PropertyName, VbGet
ExistProperty =
(
Err
.Number
=
0
)
Err
.Clear
End
Function
Exemple d'utilisation :
Dim
Ctrl As
Control
For
Each
Ctrl In
Me.Controls
If
Not
ExistProperty
(
Ctrl, "ForeColor"
) Then
Debug.Print
"La propriété ForeColor n'existe pas pour le controle "
&
Ctrl.Name
End
If
Next
Dans Projets -> Composants -> Cocher Microsoft Windows Common Controls 6.0 (SP4)
Le code suivant ne fonctionne que sous Win 2000 et supérieur mais le deuxième code proposé palie à ce manque et fonctionne sous Win 98.
Sur une feuille, poser un contrôle ToolBar et copier le code dans la partie déclaration :
Private
Type
POINTAPI
X As
Long
Y As
Long
End
Type
Private
Declare
Function
GetCursorPos Lib
"user32"
(
lpPoint As
POINTAPI) As
Long
Private
Declare
Function
SetCursorPos Lib
"user32"
(
ByVal
X As
Long
, ByVal
Y As
Long
) As
Long
Private
Declare
Sub
mouse_event Lib
"user32"
(
ByVal
dwFlags As
Long
, ByVal
dx As
Long
, _
ByVal
dy As
Long
, ByVal
cButtons As
Long
, ByVal
dwExtraInfo As
Long
)
Private
Sub
Form_Load
(
)
Dim
i As
Integer
Dim
btn As
Button
' Ajoute un objets Button au contrôle Toolbar.
Set
btn =
Toolbar1.Buttons.Add
(
Caption:=
"Test"
, Style:=
tbrDropdown)
' Ajoute deux objets ButtonMenu à l'objet Button.
btn.ButtonMenus.Add
Text:=
"Option 1"
btn.ButtonMenus.Add
Text:=
"Option 2"
End
Sub
Private
Sub
Toolbar1_ButtonClick
(
ByVal
Button As
MSComctlLib.Button
)
Dim
dx As
Long
Dim
dy As
Long
Dim
Point As
POINTAPI
With
Button
If
.Style
=
tbrDropdown Then
If
.ButtonMenus.Count
=
0
Then
Exit
Sub
dx =
(
Me.Left
+
Toolbar1.Left
+
.Left
+
.Width
) /
Screen.Width
*
65535
dy =
(
Me.Top
+
Toolbar1.Top
+
.Top
+
.Height
) /
Screen.Height
*
65535
GetCursorPos Point
mouse_event &
H8003, dx, dy, 0
, 0
mouse_event &
H8004, dx, dy, 0
, 0
SetCursorPos Point.X
, Point.Y
End
If
End
With
End
Sub
Private
Sub
Toolbar1_ButtonMenuClick
(
ByVal
ButtonMenu As
MSComctlLib.ButtonMenu
)
Select
Case
ButtonMenu.Index
Case
1
MsgBox
"Vous avez cliquer sur l'option 1"
Case
2
MsgBox
"Vous avez cliquer sur l'option 2"
End
Select
End
Sub
Pour Win 98 : Avec un bouton normal et le déroulement d'un menu quand on clique dessus.
Private
Sub
Toolbar1_ButtonClick
(
ByVal
Button As
MSComctlLib.Button
)
If
Button.Index
=
1
Then
PopupMenu lemenu, , Button.Left
, Button.Top
+
Button.Height
+
Toolbar1.Top
+
12
End
If
End
Sub
Le menu est créé dans l'éditeur de menu de la form.
Créez un fichier Manifest comme suit: (dans le bloc note de windows par exemple)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
manifestVersion
=
"1.0"
>
<assemblyIdentity
type
=
"win32"
name
=
"Microsoft.Windows.Editeur"
processorArchitecture
=
"X86"
version
=
"4.4.0.0"
/>
<description>
Entrez la description du programme ici</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type
=
"win32"
name
=
"Microsoft.Windows.Common-Controls"
language
=
"*"
processorArchitecture
=
"X86"
version
=
"6.0.0.0"
publicKeyToken
=
"6595b64144ccf1df"
/>
</dependentAssembly>
</dependency>
</assembly>
et sauvegardez-le avec le nom et l'extension du fichier exécutable pour lequel il est destiné. Exemple: J'ai un programme qui s'appelle "CSBar.exe", si je veux faire un manifest pour ce fichier exécutable, le fichier manifest aura pour nom "CSBar.exe.manifest" Pour finir, dans le module de code de votre Form principale, mettez le code suivant:
'Déclaration des API
Private
Declare
Function
InitCommonControls Lib
"comctl32.dll"
(
) As
Long
Private
Sub
Form_Initialize
(
)
'Initialise les controles pour leur donner le style de Windows XP.
InitCommonControls
End
Sub
Compilez votre programme et lancez-le, vous pourrez voir que vos contrôles on désormais le style de Windows XP.
Lien : Donner le style Windows XP aux contrôles dans l'IDE de Visual Basic 6
Mettez ce code dans un module :
Private
Type
SHFILEOPSTRUCT
hWnd As
Long
wFunc As
Long
pFrom As
String
pTo As
String
fFlags As
Integer
fAnyOperationsAborted As
Boolean
hNameMappings As
Long
lpszProgressTitle As
String
End
Type
Private
Declare
Function
SHFileOperation Lib
"shell32.dll"
Alias "SHFileOperationA"
(
lpFileOp As
SHFILEOPSTRUCT) As
Long
Private
Const
FO_COPY =
&
H2
Private
Const
FOF_ALLOWUNDO =
&
H40
Public
Sub
CopyFileWindowsWay
(
SourceFile As
String
, DestinationFile As
String
)
Dim
lngReturn As
Long
Dim
typFileOperation As
SHFILEOPSTRUCT
With
typFileOperation
.hWnd
=
0
.wFunc
=
FO_COPY
.pFrom
=
SourceFile &
vbNullChar
&
vbNullChar
.pTo
=
DestinationFile &
vbNullChar
&
vbNullChar
.fFlags
=
FOF_ALLOWUNDO
End
With
lngReturn =
SHFileOperation
(
typFileOperation)
If
lngReturn <>
0
Then
MsgBox
Err
.LastDllError
, vbCritical
Or
vbOKOnly
Else
If
typFileOperation.fAnyOperationsAborted
=
True
Then
MsgBox
"Operation Failed"
, vbCritical
Or
vbOKOnly
End
If
End
If
End
Sub
Appel de la procédure :
Call
CopyFileWindowsWay
(
App.Path
&
"\denoxaut.732"
, App.Path
&
"\messanger\denoxaut.732"
)
Ouvrir un module (page de code) :
- menu Projet puis Composants
- Onglet Contrôle
- Cochez Microsoft Common Dialog Control
Dans la barre d'outils, choisissez le control Microsoft Common Dialog Control et placez le sur le formulaire. Nous le nommons Dlg.
Placez le code suivant dans un module (action click du bouton Btn_Chercher) :
Private
Sub
Btn_Chercher_Click
(
)
With
dlg
.DialogTitle
=
"selectionner un fichier"
'titre de la boite
.FileName
=
"*.txt"
'on recherche un fichier d'extension txt
.initDir
=
"c:\"
'repertoire par defaut
.CancelError
=
false
'pour ne pas partir en erreur si on click sur annuler
.ShowOpen
End
With
'txtPath est la zone de texte recevant le chemin du fichier
txtPath =
dlg.FileName
End
Sub
Lien : Afficher la boîte de dialogue ouvrir afin de récupérer le nom et le chemin du fichier sélectionné
Lien : Afficher la boîte de dialogue Enregistrer sous afin de récupérer le nom et le chemin du fichier sélectionné
Lien : Comment sélectionner plusieurs extensions dans le filtre d'un CommonDialog ?
Pour utiliser le CommonDialog, il faut cocher le composant Microsoft Common Dialog Control 6.0 (SP2) et utiliser ce code :
CommonDialog1.Filter
=
"Fichier zip et rar (*.zip,*.rar)|*.zip;*.rar"
Placer un composant RichTextBox sur votre feuille (Microsoft Rich Textbox Control 6.0 (SP4)) et le code suivant :
Private
Declare
Function
SendMessage Lib
"user32.dll"
Alias "SendMessageA"
(
_
ByVal
hwnd As
Long
, _
ByVal
wMsg As
Long
, _
ByVal
wParam As
Long
, _
ByRef
lParam As
Any) As
Long
Private
Const
WM_PASTE As
Long
=
&
H302
Private
Sub
Form_Load
(
)
Clipboard.Clear
Clipboard.SetData
LoadPicture
(
"c:\bitmap.bmp"
)
SendMessage RichTextBox1.hwnd
, WM_PASTE, 0
, 0
End
Sub
Une Combobox standard en VB6 n'a pas de propriété "MatchEntry"
Il est toutefois possible de faire de l'auto-complétion dans une Combobox avec le code suivant :
Private
Sub
Combo1_Change
(
)
Dim
i As
Integer
, start As
Integer
start =
Len
(
Combo1.Text
)
For
i =
0
To
Combo1.ListCount
-
1
If
Left
(
Combo1.List
(
i), start) =
Combo1.Text
Then
Combo1.Text
=
Combo1.List
(
i)
End
If
Next
Combo1.SelStart
=
start
Combo1.SelLength
=
Len
(
Combo1.Text
)
End
Sub
Une autre méthode en utilisant l'API Windows :
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
Const
CB_ERR As
Long
=
(-
1
)
Private
Const
CB_SELECTSTRING As
Long
=
&
H14D
Private
Sub
Combo1_Change
(
)
Dim
start As
Integer
start =
Len
(
Combo1.Text
)
If
SendMessage
(
Combo1.hwnd
, CB_SELECTSTRING, ByVal
Combo1.ListIndex
, ByVal
Combo1.Text
) <>
CB_ERR Then
Combo1.SelStart
=
start
Combo1.SelLength
=
Len
(
Combo1.Text
)
End
If
End
Sub