La toolbar
Avant propos...
Si vous avez une erreur de compilation sur InitCommonControls(), c'est certainement parce que vous n'avez pas la librairie COMCTL32.LIB dans votre projet (C'est le cas par défaut).
Sous Visual C++ le menu Project/settings et dans l'onglet link, ajoutez COMCTL32.LIB
Sous Dev-C++, le menu Project/Project options et dans le champ Further object files or linker options blablabla, ajoutez C:\Dev-C++\Lib\libcomctl32.a via le bouton (Le chemin peut varier suivant votre installation de Dev-C++. Mais dans tous les cas, cette librairie se trouve dans le répertoire Lib de Dev-C++).
Une toolBar est une série de boutons qui s'affiche en haut de votre fenêtre, juste devant la zone cliente.
En général, on y retrouvera des options déjà présentes dans votre menu, mais qui sont très souvent utilisés par l'utilisateur. L'utilisateur ira donc plus vite dans sa tâche.
Tout ne sera pas décrit ici sur la toolbar. On trouvera toutes les informations utiles sur la toolbar à l'adresse suivante : Microsoft
Initialisation DLL
Avant toutes choses, il faut vérifier que la DLL est bien chargée:InitCommonControls() ou InitCommonControlsEx().
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_BAR_CLASSES;
InitCommonControlsEx(&icex);
Création d'une toolbar
Pour se créer un toolbar:
Deux fonctions sont disponibles:
- CreateToolbarEx, mais qui n'est plus à utiliser !
- Et une fonction déjà bien connue : CreateWindow() ou CreateWindowEx()
Il suffit d'indiquer que l'on va se créer une fenêtre fille dans notre fenêtre dans laquelle doit apparaître la toolbar en indiquant la classe TOOLBARCLASSNAME.
Par exemple :
hwndTB = CreateWindowEx(0, TOOLBARCLASSNAME, (LPSTR) NULL, WS_CHILD, 0, 0, 0, 0, hwndParent, (HMENU) ID_TOOLBAR, hinst, NULL);
hwndParent étant la fenêtre parent, ID_TOOLBAR étant un identiant que nous passons pour reconnaître la fenêtre fille lorsque celle-ci voudra communiquer avec nous. hinst étant l'instance de notre application.
Il est possible
de préciser un style à la toolbar. Il y a les styles classiques
pour une fenêtre, mais aussi des spécifiques:
Valeur | Désignation |
CCS_BOTTOM | La toolbar apparaîtra en bas de la fenêtre après la zone cliente |
CCS_TOP | (Par défaut) La toolbar apparaîtra en haut de la fenêtre avant la zone cliente |
TBSTYLE_FLAT | Les boutons sont transparents |
TBSTYLE_TRANSPARENT | (Par défaut) Les boutons sont visibles |
TBSTYLE_WRAPABLE | Si la ligne devient trop petite pour afficher tous les boutons, les boutons seront affichés sur plusieurs lignes |
TBSTYLE_TOOLTIPS | Va permettre de créer un tooltip |
... | |
... | |
... |
Il y a encore d'autres options, non étudiées pour le moment.
Afficher les boutons de la toolbar
Après avoir créé une toolbar, reste à définir ce qu'elle va contenir. Pour cela, nous devrons passer ces informations via des messages. Nous utiliserons donc la fonction SendMessage().
Pour rester
compatible avec les vieux systèmes, il faut tout d'abord envoyer le message
suivant juste après la création d'un toolbar:
SendMessage(hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
Nous allons ainsi indiquer la taille d'un élément d'un tableau de type TBBUTTON.
Un tableau de type TBBUTTON contiendra toutes les informations nécessaire à une ToolBar pour afficher les boutons.
La structure de ce tableau est la suivante:
typedef struct _TBBUTTON {
int iBitmap;
int idCommand;
BYTE fsState;
BYTE fsStyle;
DWORD dwData;
int iString;
} TBBUTTON, NEAR* PTBBUTTON, FAR* LPTBBUTTON;
typedef const TBBUTTON FAR* LPCTBBUTTON;
Avec
iBitmap Index d'un bitmap contenu dans une liste de bitmap définie dans
la toolbar (Commençant par 0). I_IMAGENONE pour indiquer
qu'il n'y a pas d'imge.
idCommand Identifiant d'un bouton. Cette valeur étant renvoyé
dans le message WM_COMMAND par la toolbar pour indiqer le bouton sélectionné.
fsState Etat du bouton (activé, caché, ...). On peut bien sûr
combiner les états en utilisant le |.
Valeur | Désignation |
TBSTATE_CHECKED | Le bouton est chécké. Mais il faut que le style du bouton soit à TBSTYLE_CHECK ! |
TBSTATE_ELLIPSES | Dessine une ellipse |
TBSTATE_ENABLED | Le bouton est actif (Donc par défaut, il ne l'est pas !) |
TBSTATE_HIDDEN | Cacher le bouton |
TBSTATE_INDETERMINATE | Le bouton est grisé, indéterminé. |
TBSTATE_MARKED | Le bouton est marqué. L'interprétation de cet état étant laissé libre... |
TBSTATE_PRESSED | Le bouton est enfoncé, comme pressé. |
TBSTATE_WRAP | Le bouton suivant sera à la ligne. |
fsStyle Style du bouton. On peut bien sûr combiner les styles en utilisant
le |.
Dans le tableau qui suit, x peut être BTNS à partir de la version 5.8 du control, sinon, il faut utiliser TBSTYLE ...
Valeur | Désignation |
x_AUTOSIZE | La toolbar choisira la taille du bouton en fonction de la taille du texte ou de l'image |
x_BUTTON | Bouton standard |
x_CHECK | Bouton toggle |
x_CHECKGROUP | Ensemble de bouton toggle. Si un bouton est choisi, celui qui avait été sélectionné précédemment perdra sa sélection automatiquement. (combinaison de x_CHECK | x_GROUP |
x_GROUP | Permet de définir un groupe. A utiliser avec x_CHECK |
x_SEP | Séparateur |
... | |
... | |
... |
Il y a encore d'autres options, non étudiées pour le moment.
dwData Valeur que l'on peut passer...
iString Index d'un texte dans la liste de texte passée à la toolbar
par le message TB_ADDSTRING. Cette index commence par zéro.
On peut aussi passer une adresse sur un texte si ce texte n'est pas dans la
liste. Voir la suite...
Boutons avec du texte
Commençons simplement avec du texte ! Même si ce n'est plus vraiment utilisé !!!
Il existe plusieurs solutions pour afficher du texte dans les boutons
- Soit l'affichage des boutons en indiquant le texte de ce bouton.
Il faut d'abord créer un tableau TBBUTTON de n éléments où n représente le nombre de bouton à afficher
Par exemple TBBUTTON tbb[n];
Puis des chaînes de caractères
char szBuf [100] = "Essai";
tbb[0].iBitmap = -1;
tbb[0].idCommand = N° ID;
tbb[0].fsState = TBSTATE_ENABLED;
tbb[0].fsStyle = BTNS_BUTTON;
tbb[0].dwData = 0;
tbb[0].iString = INT &szBuf;
Puis on utilisera le message TB_ADDBUTTONS pour indiquer à la toolbar les boutons à afficher.
SendMessage(hwndTB, TB_ADDBUTTONS, (WPARAM) NUM_BUTTONS,
(LPARAM) (LPTBBUTTON) &tbb);
NUMBUTTONS contenant le nombre de boutons à afficher.
Il faudra enfin afficher la toolbar:
SendMessage(hwndTB, TB_AUTOSIZE, 0, 0);
ShowWindow(hwndTB, SW_SHOWNORMAL);
D'où l'exemple suivant:
- Soit l'affichage des boutons en passant un identifiant sur un texte passé au préalable comme liste à la toolbar.
L'affichage de boutons dans la toolbar se fait en deux étapes:
Il faut tout d'abord définir la liste des textes qui pourront être affichés.
Ensuite, on indiquera la liste des boutons à afficher en associant chacun des boutons avec un élément de la liste des textes.
Pour définir la liste des textes, nous utiliserons le message TB_ADDSTRING
idText = SendMessage( (HWND) hWndControl, (UINT) TB_ADDSTRING, (WPARAM) (HINSTANCE)
hinst, (LPARAM) MAKELONG (idString, 0) );
En entrée:
hinst Pointeur sur l'instance de notre application si la liste est définie par un identifiant de type ressource string. A 0 si la liste sera passée par un tableau de 1 à n éléments.
idString identifiant de la ressource string si hinst est différent de 0. Sinon, il s'agit d'une adresse sur un tableau contenant 1 ou plusieurs textes à transmettre. Chacun des textes devant se terminer par 0. Pour indiquer la fin du tableau, il faudra passer 0, 0 à la fin de celui-ci.
En sortie:
-1 si problème, sinon, identifiant de la première chaîne passée, sachant que pour les autres, leur valeur correspondante est la valeur de l'identifiant + n ou n est la position du texte dans le tableau (en commençant par 0 !)
Voici
un exemple de code utilisant une liste.
On peut aussi stocker son texte dans une ressource et le relire dans le code...
LoadString(hInst, ID_TEXT, (LPSTR) &szBuf, MAX_LEN);
iTexte = SendMessage(hwndTB, TB_ADDSTRING, 0, (LPARAM) (LPSTR) &szBuf);
Boutons avec des images prédéfinies
Le principe est identique à celui du texte, sauf que nous allons afficher des images déjà définies dans la barre d'outils à partir d'un ensemble d'images.
Ils existent différents ensembles d'images pré-définies:
Valeurs |
IDB_STD_LARGE_COLOR |
IDB_STD_SMALL_COLOR |
IDB_VIEW_LARGE_COLOR |
DB_VIEW_SMALL_COLOR |
Ces ensembles contiennent jusqu'à 15 images:
Valeurs | Désignation |
STD_COPY | Copier |
STD_CUT | couper |
STD_DELETE | Effacer |
STD_FILENEW | Créer un fichier |
STD_FILEOPEN | Ouvrir un fichier |
STD_FILESAVE | Sauver un fichier |
STD_FIND | Chercher |
STD_HELP | Aide |
STD_PASTE | Coller |
STD_PRINT | Imprimer |
STD_PRINTPRE | Prévisualisation avant impression |
STD_PROPERTIES | Propriétés |
STD_REDOW | Refaire |
STD_REPLACE | Remplace |
STD_UNDO | Défaire |
La première chose à faire sera donc de définir l'ensemble à utiliser:
Nous utiliserons pour cela le message TB_ADDBITMAP
SendMessage (hwndTB, TB_ADDBITMAP, NULL, (LPARAM)&tbaddbitmap);
wParam ne servant pas dans ce cas particulier, on le mettra à NULL. De toute façon, il est ignoré.
lParam devant contenir un pointeur sur une structure de type TBADDBITMAP.
typedef struct {
HINSTANCE hInst;
UINT_PTR nID;
} TBADDBITMAP, *LPTBADDBITMAP;
Avec
hInst positionné ici à HINST_COMMCTRL. Pour indiquer que nous allons utiliser les images pré-définies dans la ToolBar.
nID Contenant l'identifiant de l'ensemble à utiliser.
Par exemple:
...
tbaddbitmap.hInst = HINST_COMMCTRL ;
tbaddbitmap.nID = VIEW_LARGEICONS; //iStandardId[index];
SendMessage (hwndTB, TB_ADDBITMAP, NULL, (LPARAM)&tbaddbitmap);
...
Nous utiliserons ensuite le message TB_ADDBUTTONS avec à nouveau la structure LPTBBUTTON pour indiquer les boutons à afficher.
La différence par rapport aux textes: nous allons indiquer dans le membre iBitmap l'index d'une ou des images parmis les 15 images disponibles de l'ensemble (des images) choisi (!) (Par exemple tbb.iBitmap = STD_COPY).
D'où l'exemple
Affichage
des 15 images de VIEW_LARGEICONS
Boutons avec nos images
D'abord il faudra dessiner les boutons, il faudra donc avoir des talents artistiques avant tout...où chercher des images toutes faites sur internet !
Ensuite, il faut connaître la taille des boutons. Sachant que tous les boutons devrons avoir la même taille dans la toolbar !
Tous ces boutons devront enfin se retouver dans un seul fichier BMP. Tous les boutons collés les uns à la suite des autres et, je me répète, ayant tous la même taille !
Par exemple:
Ensuite, reste à déclarer tout cela à la toolbar:
La taille des images sera indiquée par le message TB_SETBITMAPSIZE (par défaut, il est à 16/15)
SendMessage (hwndTB, TB_SETBITMAPSIZE, NULL, MAKELONG (32,32));
Ensuite, le message TB_ADDBITMAP
stdidx = SendMessage (hwndTB, TB_ADDBITMAP, 6, (LPARAM)&tbaddbitmap);
wParam est ici à 6, car on va indiquer le nombre de boutons présent dans le fichier bitmap.
lParam contient une adresse sur une structure de type tbaddbitmap:
Cette fois-ci, nous y indiquerons:
Dans le cas où l'image serait une ressource de notre programme avec l'id qui serait IDR_TOOLBAR1:
tbaddbitmap.hInst = hInst ; // L'instance de notre programme
tbaddbitmap.nID = IDR_TOOLBAR1; // L'id de notre ressource
où, s'il s'agit d'un bmp chargé:
tbaddbitmap.hInst =NULL ;
tbaddbitmap.nID = handle du BMP
En sortie de ce message, nous obtenons l'index de la première image. Cet index sera à 0 si votre liste était vide. Où tout autre valeur si vous aviez déjà chargé des images précédement dans votre toolbar.
Ensuite, il faut charger TBBUTTON comme déjà indiqué précédement...
Voilà, c'est tout simple.
On peut aussi
ajouter des images personnelles après avoir déclaré l'utilisation
d'une liste d'image prédéfinie. Vous pourrez alors utiliser toutes
les images présentes dans la liste ainsi mise à jour.
Connaître les boutons pressés par l'utilisateur
Bin oui, c'est bien beau de dessiner, mais comment savoir le bouton pressé par l'utilisateur ???
Et bien grâce à ce que nous avons rempli dans TBBUTTON...plus exactement grâce au membre idCommand
Ce champ va contenir l'identifant du bouton.
La toolbar va envoyer sous forme de message l'identifiant du bouton pressé par l'utilisateur. Le message sera envoyé à la procédure de gestion des messages de notre fenêtre (parent de la toolbar).
Le message sera le bien connu WM_COMMAND.
Pour ne pas confondre avec un message de menu, ou de tout autre objet, il sera nécessaire de tester la valeur de lParam qui devra contenir ici le handle de la fenêtre de notre toolbar.
Si cela correspond, alors wParam contiendra l'identifiant du bouton pressé...
C'est vraiment trop simple !
ToolTip dans une ToolBar
Il est possible de définir des tooltips pour chacun des boutons qui seront survolés. Mais, sans être très compliqué, ce n'est pas une chose facile !
Il faut définir tout d'abord un nouveau style (TBSTYLE_TOOLTIPS) dans la toolbar pour permettre l'utilisation des toolstips:
Par exemple
hwndTB = CreateWindowEx(0, TOOLBARCLASSNAME, (LPSTR) NULL, WS_CHILD | CCS_TOP
| TBSTYLE_TOOLTIPS,
0, 0, 0, 0, hwnd, (HMENU) ID_TOOLBAR, hInst, NULL);
Puis il faudra traiter un nouveau message:
A chaque fois que la toolbar aura besoin d'afficher un tooltip, il demandera à notre fenêtre parent le message à afficher.
Il nous faudra donc traiter le message WM_NOTIFY avec le code suivant :TTN_GETDISPINFO. Par exemple de la manière suivante: