La toolbar

 

Avant propos...

Image non trouvée !

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.

Image non trouvée !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().

 

Image non trouvée !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:

Image non trouvée !

 

- 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 !)

Image non trouvée !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

Image non trouvée !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:

Image non trouvée !

 

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.

Image non trouvée !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: