API Windows en C

Le contrôle Toolbar

CGi

Le contrôle Toolbar. ♪

- Titre : API Windows en C

- Auteur : CGi

- Parution : 23 juillet 2005

- Mise à jour : 4 janvier 2013

- Licence : Copyright ® 2005 CGi. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- I-A. Mise en œuvre

- II. Code complet

- II-A. resource.h

- II-B. resource.rc

- II-C. winmain.c

- III. Utilisation d'images personnelles

I - Introduction

Nous allons aborder un autre contrôle de la « Common control library » : Le contrôle Toolbar.

Pour cet exemple on reprendra l'exemple « Communiquer avec les boîtes de dialogue ». On lui ajoutera une Toolbar avec trois boutons. Dans cet exemple les boutons auront des grandes images et un texte, la Toolbar aura le style flat.

I-A - Mise en œuvre

Le contrôle Toolbar se construit traditionnellement avec la fonction CreateWindow ou CreateWindowEx.

1. htb = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,

2. WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT,

3. 0, 0, 0, 0, hwnd, NULL, hinst, NULL);

La Toolbar possède sa propre liste d'images. Nous devons juste la remplir. Pour cela on utilise une structure TBADDBITMAP avec son champ hInst initialisé avec le handle d'instance du fichier contenant les images et son champ nID avec l'identificateur de la ressource image. Dans notre exemple nous nous faciliterons la tâche en prenant des images standard de Windows (champ hInst à HINST_COMMCTRL et champ nID à IDB_STD_LARGE_COLOR pour de grandes images. Ensuite on envoie le message TB_ADDBITMAP à la Toolbar avec l'adresse de la structure comme paramètre.

1. TBADDBITMAP tbab;

3. tbab.hInst =  HINST_COMMCTRL ;

4. tbab.nID   =  IDB_STD_LARGE_COLOR;

5. SendMessage(htb, TB_ADDBITMAP, 1, (WPARAM)&tbab);

Ensuite il faut ajouter les boutons à la Toolbar. Pour cela nous devons tout d'abord remplir un tableau de structure TBBUTTON. Chaque élément du tableau correspond à un bouton. Le champ iBitmap de la structure reçoit l'indice de l'image, le champ idCommand reçoit l'identificateur de la commande. Ce peut être la même que celle d'une option de menu. Ce sera d'ailleurs le cas dans l'exemple. Le champ fsState reçoit l'état du bouton. Le champ fsStyle reçoit le style du bouton. Le troisième bouton dans l'exemple a le style TBSTYLE_SEP car c'est un séparateur. Le champ iString reçoit l'indice de la chaîne de caractères qui correspond au bouton. Elle doit être préalablement chargée dans la liste de chaîne de la Toolbar en lui envoyant un message TB_ADDSTRING.

1. TBBUTTON tbb[4];

3. tbb[0].iBitmap = STD_FILENEW;

4. tbb[0].idCommand = IDM_NEW;

5. tbb[0].fsState = TBSTATE_ENABLED;

6. tbb[0].fsStyle = TBSTYLE_BUTTON;

7. tbb[0].dwData = 0;

8. tbb[0].iString = SendMessage(htb, TB_ADDSTRING, 0,

9. (LPARAM)"Nouveau");

10. tbb[1].iBitmap = STD_PROPERTIES;

11. tbb[1].idCommand = IDM_PARAM;

12. tbb[1].fsState = TBSTATE_ENABLED;

13. tbb[1].fsStyle = TBSTYLE_BUTTON;

14. tbb[1].dwData = 0;

15. tbb[1].iString = SendMessage(htb, TB_ADDSTRING, 0,

16. (LPARAM)"Paramètre");

17. tbb[2].iBitmap = 0;

18. tbb[2].idCommand = -1;

19. tbb[2].fsState = 0;

20. tbb[2].fsStyle = TBSTYLE_SEP;

21. tbb[2].dwData = 0;

22. tbb[2].iString = -1;

24. tbb[3].iBitmap = STD_HELP;

25. tbb[3].idCommand = IDM_ABOUT;

26. tbb[3].fsState = TBSTATE_ENABLED;

27. tbb[3].fsStyle = TBSTYLE_BUTTON;

28. tbb[3].dwData = 0;

29. tbb[3].iString = SendMessage(htb, TB_ADDSTRING, 0,

30. (LPARAM)"À propos");

31. SendMessage(htb, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);

32. SendMessage(htb, TB_ADDBUTTONS, 4, (LPARAM)&tbb);

33. SendMessage(htb, TB_AUTOSIZE, 0, 0);

Quand le tableau est rempli, il faut ajouter les boutons à la Toolbar en lui envoyant un message TB_ADDBUTTONS avec l'adresse du tableau comme paramètre. Avant d'envoyer ce message, il est important d'envoyer la taille de la structure TBBUTTON à la Toolbar en lui envoyant un message TB_BUTTONSTRUCTSIZE. Pour adapter la taille de la Toolbar à celle des boutons, on lui envoie un message TB_AUTOSIZE. Pour voir toutes les possibilités de la Toolbar, je vous propose de consulter l'aide API Win32.

II - Code complet

II-A - resource.h

1. #define IDM_QUIT  1

2. define IDM_NEW   2

3. #define IDM_ABOUT 3

4. #define IDM_PARAM 4

6. #define IDE_EDIT1 101

II-B - resource.rc

1. #include <windows.h>

3. #include "resource.h"

5. 1 ICON icone.ico

6. 2 ICON autre.ico

8. LEMENU MENU

9. BEGIN

10. POPUP "Fichier"

11. BEGIN

12. MENUITEM "&Nouveau", IDM_NEW

13. MENUITEM "&Paramètres...", IDM_PARAM

14. MENUITEM SEPARATOR

15. MENUITEM "Quitter\tAlt+F4", IDM_QUIT

16. END

17. POPUP "Aide"

18. BEGIN

19. MENUITEM "À propos...", IDM_ABOUT

20. END

21. END

23. DIALOG2 DIALOG

24. 60, 60, 182, 70

25. STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

26. CAPTION "Paramètres"

27. BEGIN

28. DEFPUSHBUTTON "OK", IDOK, 36, 42, 42, 12

29. PUSHBUTTON "Cancel", IDCANCEL, 96, 42, 42, 12

30. EDITTEXT IDE_EDIT1, 88, 15, 74, 12

31. LTEXT "Titre de la fenêtre", -1, 24, 18, 60, 10

32. END

34. DIALOG1 DIALOG

35. 60, 60, 160, 80

36. STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

37. CAPTION "À propos"

38. BEGIN

39. DEFPUSHBUTTON "OK", IDOK, 56, 50, 42, 12

40. ICON 2, -1, 20, 15, 32, 32

41. LTEXT "Mon beau programme !", -1, 60, 18, 80, 10

42. END

II-C - winmain.c

1. #include <windows.h>

2. #include <commctrl.h>

4. #include "resource.h"

6. HINSTANCE hinst;

8. LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);

9. BOOL APIENTRY Dialog1Proc(HWND, UINT, WPARAM, LPARAM);

10. BOOL APIENTRY Dialog2Proc(HWND, UINT, WPARAM, LPARAM);

12. int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance,

13. LPSTR lpCmdLine, int nCmdShow)

14. {

15. HWND hwnd;

16. MSG msg;

17. WNDCLASS wc;

19. hinst = hinstance;

21. wc.style = 0 ;

22. wc.lpfnWndProc = MainWndProc;

23. wc.cbClsExtra = 0;

24. wc.cbWndExtra = 0;

25. wc.hInstance = hinstance;

26. wc.hIcon = LoadIcon(hinstance,MAKEINTRESOURCE(2));

27. wc.hCursor = LoadCursor(NULL, IDC_ARROW);

28. wc.hbrBackground = NULL;

29. wc.lpszMenuName =  "LEMENU";

30. wc.lpszClassName = "MaWinClass";

32. if(!RegisterClass(&wc)) return FALSE;

34. hwnd = CreateWindow("MaWinClass", "Titre", WS_OVERLAPPEDWINDOW,

35. CW_USEDEFAULT, CW_USEDEFAULT, 400, 300,

36. NULL, NULL, hinstance, NULL);

37. if (!hwnd)  return FALSE;

39. ShowWindow(hwnd, nCmdShow);

41. while (GetMessage(&msg, NULL, 0, 0))

42. {

43. TranslateMessage(&msg);

44. DispatchMessage(&msg);

45. }

46. return msg.wParam;

47. }

48. /****************************************************************************/

50. LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

51. {

52. static HWND hEdit;

54. static HWND htb;

56. static BOOL EditNotChg = TRUE;

57. switch (uMsg)

58. {

59. case WM_CREATE:

60. {

61. TBADDBITMAP tbab;

62. TBBUTTON tbb[4];

64. HFONT hFont;

65. hEdit = CreateWindowEx(WS_EX_CLIENTEDGE ,"edit", "Texte",

67. WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL,

68. 0, 0, 0, 0, hwnd, NULL, hinst, NULL);

69. hFont = (HFONT)GetStockObject(ANSI_FIXED_FONT);

70. SendMessage(hEdit,WM_SETFONT,(UINT)hFont,TRUE);

71. SendMessage(hEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN,

72. MAKELONG(5, 5));

74. InitCommonControls();

76. htb = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,

77. WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT,

78. 0, 0, 0, 0, hwnd, NULL, hinst, NULL);

80. tbab.hInst =  HINST_COMMCTRL ;

81. tbab.nID   =  IDB_STD_LARGE_COLOR;

82. SendMessage(htb, TB_ADDBITMAP, 1, (WPARAM)&tbab);

84. tbb[0].iBitmap = STD_FILENEW;

85. tbb[0].idCommand = IDM_NEW;

86. tbb[0].fsState = TBSTATE_ENABLED;

87. tbb[0].fsStyle = TBSTYLE_BUTTON;

88. tbb[0].dwData = 0;

89. tbb[0].iString = SendMessage(htb, TB_ADDSTRING, 0,

90. (LPARAM)"Nouveau");

91. tbb[1].iBitmap = STD_PROPERTIES;

92. tbb[1].idCommand = IDM_PARAM;

93. tbb[1].fsState = TBSTATE_ENABLED;

94. tbb[1].fsStyle = TBSTYLE_BUTTON;

95. tbb[1].dwData = 0;

96. tbb[1].iString = SendMessage(htb, TB_ADDSTRING, 0,

97. (LPARAM)"Paramètre");

98. tbb[2].iBitmap = 0;

99. tbb[2].idCommand = -1;

100. tbb[2].fsState = 0;

101. tbb[2].fsStyle = TBSTYLE_SEP;

102. tbb[2].dwData = 0;

103. tbb[2].iString = -1;

105. tbb[3].iBitmap = STD_HELP;

106. tbb[3].idCommand = IDM_ABOUT;

107. tbb[3].fsState = TBSTATE_ENABLED;

108. tbb[3].fsStyle = TBSTYLE_BUTTON;

109. tbb[3].dwData = 0;

110. tbb[3].iString = SendMessage(htb, TB_ADDSTRING, 0,

111. (LPARAM)"À propos");

113. SendMessage(htb, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);

114. SendMessage(htb, TB_ADDBUTTONS, 4, (LPARAM)&tbb);

115. SendMessage(htb, TB_AUTOSIZE, 0, 0);

116. return 0;

117. }

119. case WM_CLOSE:

120. if(EditNotChg ||

121. MessageBox(hwnd,"Le texte a été modifié.\r\nÊtes-vous sûr de \

122. vouloir fermer l'application ?"

123. ,"Question ?",MB_YESNO | MB_ICONQUESTION ) == IDYES)

124. DestroyWindow(hwnd);

125. return 0;

127. case WM_COMMAND:

128. if(LOWORD(wParam) == IDM_QUIT) PostMessage(hwnd, WM_CLOSE,0,0);

129. if(LOWORD(wParam) == IDM_NEW)

130. if(EditNotChg ||

131. MessageBox(hwnd,"Le texte a été modifié.\r\nÊtes-vous de \

132. vouloir fermer votre travail ?"

133. ,"Question ?",MB_YESNO | MB_ICONQUESTION ) == IDYES)

134. {

135. SendMessage(hEdit,WM_SETTEXT,0,(LPARAM)"");

136. EditNotChg = TRUE;

137. }

138. if(LOWORD(wParam) == IDM_ABOUT)

139. DialogBox(hinst, "DIALOG1" , hwnd, (DLGPROC)Dialog1Proc);

140. if(LOWORD(wParam) == IDM_PARAM)

141. DialogBoxParam(hinst, "DIALOG2" , hwnd,

142. (DLGPROC)Dialog2Proc, (LPARAM)hwnd);

143. if(HIWORD(wParam) == EN_CHANGE) EditNotChg = FALSE;

145. return 0;

147. case WM_SIZE:

148. {

149. RECT sbRect;

150. UINT  tbheight;

151. GetWindowRect(htb, &sbRect);

152. tbheight = sbRect.bottom - sbRect.top;

153. MoveWindow(htb, 0, 0, LOWORD(lParam), tbheight, TRUE);

154. MoveWindow(hEdit, 0, tbheight, LOWORD(lParam),

155. HIWORD(lParam)-tbheight, TRUE);

156. return 0;

157. }

159. case WM_DESTROY:

160. PostQuitMessage(0);

161. return 0;

163. default:

164. return DefWindowProc(hwnd, uMsg, wParam, lParam);

165. }

166. }

167. /*****************************************************************************/

169. BOOL APIENTRY Dialog1Proc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)

170. {

171. switch (uMsg)

172. {

173. case WM_INITDIALOG:

175. return TRUE;

177. case WM_COMMAND:

178. if (LOWORD(wParam) == IDCANCEL || LOWORD(wParam) == IDOK)

179. {

180. EndDialog(hDlg,0);

181. return TRUE;

182. }

184. default:

185. return FALSE;

186. }

187. }

188. /******************************************************************************/

190. BOOL APIENTRY Dialog2Proc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)

191. {

192. static HWND hParent;

193. switch (uMsg)

194. {

195. case WM_INITDIALOG:

196. {

197. int WindowTextLength;

198. CHAR *buffer;

199. hParent = (HWND)lParam;

200. WindowTextLength = GetWindowTextLength(hParent);

201. buffer = (CHAR*)LocalAlloc(LMEM_FIXED, WindowTextLength+1);

202. GetWindowText(hParent, buffer, WindowTextLength+1);

203. SetDlgItemText(hDlg, IDE_EDIT1, buffer);

204. LocalFree(buffer);

205. }

206. return TRUE;

208. case WM_COMMAND:

209. if (LOWORD(wParam) == IDOK )

210. {

211. CHAR st[128];

212. GetDlgItemText(hDlg, IDE_EDIT1, st, 128);

213. SetWindowText(hParent,st);

214. EndDialog(hDlg,0);

215. return TRUE;

216. }

217. if (LOWORD(wParam) == IDCANCEL )

218. {

219. EndDialog(hDlg,0);

220. return TRUE;

221. }

222. default:

223. return FALSE;

224. }

225. }

J'ai testé les compilations avec C++ Builder et DevC++.
La constante de style flat (TBSTYLE_FLAT) de la Toolbar n'est pas définie dans le fichier commctrl.h avec la version de Dev-C++ en ma possession. J'ai donc dû la remplacer par sa valeur (0x0800) :

1. htb = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,

2. WS_CHILD | WS_VISIBLE | 0x0800,

3. 0, 0, 0, 0, hwnd, NULL, hinst, NULL);

III - Utilisation d'images personnelles

Dans l'exemple précédent, nous avons utilisé des images du système. Nous allons brièvement voir comment utiliser des images personnelles. Il faut remplir une structure de type TBADDBITMAP : le champ hInst avec le handle d'instance du module contenant les images et le champ nID avec l'identificateur de la ressource image. Ensuite il suffit d'ajouter les images en envoyant le message TB_ADDBITMAP à la toolbar. Le champ iBitmap des structures TBBUTTON devra être rempli avec l'indice de l'image.

1. TBADDBITMAP tbab;

3. /* ... */

5. tbab.hInst = hinst;

6. tbab.nID = IDB_IMG;

7. SendMessage(htb, TB_ADDBITMAP, 4, (WPARAM)&tbab);

9. tbb[0].iBitmap = 5;

10. /* ... */

Plus récemment a été apportée une autre solution qui a l'avantage de pouvoir utiliser des images 32 bits. C'est d'utiliser une Liste d'images que l'on ajoutera à la toolbar.

1. HIMAGELIST himgList;

3. /* ... */

5. himgList = ImageList_Create(24, 24, ILC_MASK |ILC_COLOR32 , 0, 6);

6. ImageList_AddMasked(himgList,

7. LoadBitmap(hinst,MAKEINTRESOURCE(IDB_IMG)), 0x00FF00FF);

8. SendMessage(htb, TB_SETIMAGELIST , 0, (LPARAM)himgList);

10. tbb[0].iBitmap = 5;

11. /* ... */

Le message TB_SETIMAGELIST n'est pas défini dans le fichier commctrl.h avec la version de Dev-C++ en ma possession. J'ai donc dû définir ce message pour l'utiliser.

1. #define TB_SETIMAGELIST (WM_USER + 48)

À vos PC.

CGi

Retour au sommaire.