[FAQ][VC++]Comment placer des images sur un menu contextuel
Nous voulons placer des petites images à gauche des commandes de menus de nos menus contextuels afin qu'ils aient un look and feel de VS 2005 ou d'Office 2003, 2007 ou XP.
Pour y parvenir nous avons besoin :
1. D'un gestionnaire de menus contextuels le manager CContextMenuManager qui appliquera notre look.
2. D'une bande de petites images placées sur un seul bitmap (en 24 bits c'est plus jolie) afin de définir notre collection d'images.
3. D'une resource de type barre d'outils dans l'éditeur de resource qui identifiera les IDs des items des menus aux images sur ces items de menus.
4. Et enfin de la classe CMFCToolBar qui chargera nos images.
Premièrement pour pouvoir utiliser le gestionnaire des menus :
5. Nous avons besoin que l'objet application puisse dériver de CWinAppEx qui initialise correctement toute la famille des classes des gestionnaires dont l'un d'eux est le CContextMenuManager. Et donc on remplace toutes les occurences de CWinApp en CWinAppEx.
6. Dans la méthode InitInstance() de notre objet application nous insérons le code juste un peu avant la construction de notre frame principale ou de notre boite de dialogue :
Code:
1 2
|
InitContextMenuManager(); // construit l'unique objet gestionnaire de menus contextuels |
7. Ensuite dans l'éditeur de resource nous nous mettons à contruire nos différents menus contextuels dont voici trois menus d'exemples IDR_MENU1, IDR_MENU2 et IDR_MENU3
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
IDR_MENU1 MENU
BEGIN
POPUP "Menu1"
BEGIN
MENUITEM "Utilisateur", ID_USER
MENUITEM "Maison", ID_HOUSE
MENUITEM "Information", ID_INFORMATION
MENUITEM "Fenêtre", ID_WINDOWS
END
END
IDR_MENU2 MENU
BEGIN
POPUP "Menu2"
BEGIN
MENUITEM "Vraie", ID_TRUE
MENUITEM "False", ID_FALSE
END
END
IDR_MENU3 MENU
BEGIN
POPUP "Menu3"
BEGIN
MENUITEM "Exclamation", ID_EXCLAMATION
MENUITEM "Question", ID_QUESTION
MENUITEM "Actualiser", ID_REFRESH
MENUITEM "Aller", ID_GO
MENUITEM "Message", ID_MESSAGE
END
END |
8. Toujours dans l'éditeur de resource on prépare nos petites images (bitmap) de 16 X 16. Soient peut être 11 petites images pour chaque item de nos 3 menus contextuels. (Il n'est pas dit que chaque item de menu doit avoir une image).
On ajoute donc dans les ressources un long bitmap en 24 bits IDB_MENUS_IMAGES de (Height = 16, Width =176) pour contenir nos 11 petites images. Les petites images sont placées côte à côte sur le long bitmap (par copie-coler) dont le nom est MenuImages.bmp dans le sous dossier res de notre projet.
9. Dans l'éditeur de resource on ajoute une nouvelle barre d'outils IDR_TOOLBAR_MENUS_IMAGES. Et on se met à créer les 11 petits boutons en leur attribuant juste les IDs seulement (sans se préoccuper de l'image qui est dessus).
Ici il faut faire attention, l'ordre d'affectation des IDs des boutons de la barre d'outils doivent correspondre à 2 choses :
9a. Ils doivents impérativement êtres un des IDs des items de vos menus sinon ça ne fonctionnera pas et le menu item sera sans image.
9b. Ils doivents correspondre à l'ordre de succession des petites images qui se suivent sur le IDB_MENUS_IMAGES.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
IDR_TOOLBAR_MENUS_IMAGES TOOLBAR 16, 15
BEGIN
BUTTON ID_USER
BUTTON ID_HOUSE
BUTTON ID_INFORMATION
BUTTON ID_WINDOWS
BUTTON ID_TRUE
BUTTON ID_FALSE
BUTTON ID_EXCLAMATION
BUTTON ID_QUESTION
BUTTON ID_REFRESH
BUTTON ID_GO
BUTTON ID_MESSAGE
END |
10. Pour garantie notre look and feel nous devons inscrire nos menus contextuels dans le CContextMenuManager.
Une méthode candidate est la méthode virtuelle PreLoadState() qui surcharge celle de CWinAppEx de notre classe application.
Code:
virtual void PreLoadState();
Code:
1 2 3 4 5 6 7 8 9
|
void CMyApp::PreLoadState()
{
CContextMenuManager* pMgr = GetContextMenuManager();
pMgr->AddMenu("Menu1", IDR_MENU1);
pMgr->AddMenu("Menu2", IDR_MENU2);
pMgr->AddMenu("Menu3", IDR_MENU3);
} |
11. Dans le cas d'une application SDI ou MDI nous pouvons charger nos images dans le OnCreate() de la frame principale alors que pour une boite de dialogue dans son OnInitDialog() ainsi nous commençons par définir la taille des boutons de nos menu images
Code:
1 2
|
CMFCToolBar::SetMenuSizes(CSize(22,22), CSize(16, 16)); |
12. Ensuite pour le cas d'une application basé sur une boite de dialogue nous avons :
Code:
1 2
|
CMFCToolBar::AddToolBarForImageCollection(IDR_TOOLBAR_MENUS_IMAGES, 0, 0, IDB_MENUS_IMAGES); |
13. Pour le cas des applications SDI ou MDI. La méthode CMainFrame::OnCreate() a déjà crée la toolbar principale (standard) de l'application. Nous allons juste modifier le code légèrement en insérant dans les ressources le bitmap IDB_MAINFRAME_256 à partir du fichier existant Toolbar256.bmp de la toolbar IDR_MAINFRAME_256. Et ensuite on réécrit le code de chargement de la toolbar standard
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
//...
CMFCToolBar::SetMenuSizes(CSize(22,22), CSize(16, 16));
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(theApp.m_bHiColorIcons ? IDR_MAINFRAME_256 : IDR_MAINFRAME, 0, IDB_MAINFRAME_256))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
//...
CMFCToolBar::AddToolBarForImageCollection(IDR_TOOLBAR_MENUS_IMAGES, 0, 0, IDB_MENUS_IMAGES);
return 0;
} |
14. Et dans la vue (ici une formview) nous avons nos menus contextuels que nous affichons à l'aide du gestionnaire de menu pour nous garantir un bon look and feel en interceptant le click droit (bouton droit de la souris relevé).
Code:
1 2 3 4 5 6
|
void CMyView::OnRButtonUp(UINT nFlags, CPoint point)
{
ClientToScreen(&point);
theApp.GetContextMenuManager()->ShowPopupMenu(m_nMenuID, point.x, point.y, this, TRUE);
} |
où m_nMenuID est un des id des menus soit IDR_MENU1 ou IDR_MENU2 ou IDR_MENU3 que nous permuttons par double click.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
void CMyView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
switch(m_nMenuID)
{
case IDR_MENU1:
m_nMenuID = IDR_MENU2;
break;
case IDR_MENU2:
m_nMenuID = IDR_MENU3;
break;
case IDR_MENU3:
m_nMenuID = IDR_MENU1;
break;
}
CFormView::OnLButtonDblClk(nFlags, point);
} |
m_nMenuID est initialisé à IDR_MENU1 dans le constructeur de la vue.
N'oubliez pas d'ajouter des gestionnaires de commandes aux menus sinon les menus items sont désactivés par défaut.
Et voilà :D