|
Sorry, my mistake ! this problem has been corrected, it was my fault. But I wanted to share the case here because it could also happen to other developers :
My application had already a menu hooking class designed to include icons within menus (icons stored in a dummy toolbar in project resources).
When I implemented the CMenuXP class in my code, I forgot to remove the previous hooking functions. So it seems that Windows or MFC could not support twice hooking, or maybe functions overlapped.
Anyway, that's the bottom line : do NOT forget to remove your previous menu hooking functions before setting this new one !
See ya.
|
|
|
|
|
Thanks for this great code that allows to implement XP style on Menus, but the interface like have some lacks if it can not be completed with a XP-style toolbar, with rounded buttons like in Internet Explorer 6 under Windows XP, see what I mean ?
Is a XP-style toolbar scheduled for design ?
Otherwise, does anyone here knows were such code can be found ?
Regards,
|
|
|
|
|
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
...
// Comment this line to deactivate the XP Look & Feel
CMenuXP::SetXPLookNFeel (this);
...
}
|
|
|
|
|
|
Congratulations, very good and useful article!
I suggest a little improvement regarding the usage of toolbars with more colors than by defalt.
I am using true colors toolbars. To get this functionality three bitmaps are to be provided - normal, disabled and hot version of toolbar images.
Since CMenuXP gets its images from the standard toolbar bitmap it can not take advantage of these true color bitmaps. However, with few simple changes this functionality can be achieved and still retain the normal behavior with simple toolbars.
Changes in MenuXP.h:
Change class CImgDesc into:
class CImgDesc
{
public:
HIMAGELIST m_hImgList;
HIMAGELIST m_hImgHotList;
HIMAGELIST m_hImgDisList;
int m_nIndex;
CImgDesc (HIMAGELIST hImgList = NULL, HIMAGELIST hImgHotList = NULL, HIMAGELIST hImgDisList = NULL, int nIndex = 0)
: m_hImgList (hImgList), m_hImgHotList (hImgHotList), m_hImgDisList (hImgDisList), m_nIndex (nIndex)
{
}
};
Changes in MenuXP.cpp:
Change drawing code in CMenuItem::Draw() to:
if ( GetDisabled() || (bSelected && !GetChecked()) )
{
if(m_ImgDesc.m_hImgDisList && GetDisabled())
::ImageList_Draw (m_ImgDesc.m_hImgDisList, m_ImgDesc.m_nIndex, pDC->m_hDC,
pRect->left+3, rc.top+3, ILD_TRANSPARENT);
else
{
HICON hIcon = ImageList_ExtractIcon (NULL, m_ImgDesc.m_hImgList, m_ImgDesc.m_nIndex);
pDC->DrawState (CPoint (pRect->left + ( bOver ? 4 : 3 ), rc.top + ( bOver ? 4 : 3 )),
CSize (IMGWIDTH, IMGHEIGHT), hIcon, DSS_MONO,
CBrush (bOver ? HLS_TRANSFORM (::GetSysColor (COLOR_HIGHLIGHT), +50, -66) : HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -27, 0)));
DestroyIcon (hIcon);
}
}
if ( !GetDisabled() )
{
if(m_ImgDesc.m_hImgHotList && bSelected)
::ImageList_Draw (m_ImgDesc.m_hImgHotList, m_ImgDesc.m_nIndex, pDC->m_hDC,
pRect->left+(!GetChecked()? 2 : 3 ), rc.top+(!GetChecked()? 2 : 3 ), ILD_TRANSPARENT);
else
::ImageList_Draw (m_ImgDesc.m_hImgList, m_ImgDesc.m_nIndex, pDC->m_hDC,
pRect->left+( (bSelected && !GetChecked()) ? 2 : 3 ), rc.top+( (bSelected && !GetChecked()) ? 2 : 3 ), ILD_TRANSPARENT);
}
Change reading of the images from the toolbar in CMenuXP::SetXPLookNFeel()
CImgDesc imgDesc ((HIMAGELIST)pBar->SendMessage (TB_GETIMAGELIST, 0, 0),
(HIMAGELIST)pBar->SendMessage (TB_GETHOTIMAGELIST, 0, 0),
(HIMAGELIST)pBar->SendMessage (TB_GETDISABLEDIMAGELIST, 0, 0),tbbi.iImage);
|
|
|
|
|
Also congratulations, very good and useful extension! I tried it and it works great!
But when you also using CToolBarXP (also from Michel le Fol) you have to change some lines in CToolBarXP::OnPaint() because the grayed and hot bitmaps are not shown correctly.
I made the two following changes and it worked:
At the beginning of OnPaint() replace the line
<br />
HIMAGELIST m_hImageList = (HIMAGELIST)DefWindowProc (TB_GETIMAGELIST, 0, 0);<br />
with the three lines
<br />
HIMAGELIST m_hImageListTC = (HIMAGELIST)DefWindowProc (TB_GETIMAGELIST, 0, 0);<br />
HIMAGELIST m_hImageListHT = (HIMAGELIST)DefWindowProc (TB_GETHOTIMAGELIST,0,0);<br />
HIMAGELIST m_hImageListGR = (HIMAGELIST)DefWindowProc (TB_GETDISABLEDIMAGELIST,0,0);<br />
and at the end on OnPaint() replace
<br />
if ( !IS_ENABLED(tbbutton) || (bOver && !bPressed) )<br />
{<br />
HICON hIcon = ImageList_ExtractIcon (NULL, m_hImageList, tbbutton.iBitmap);<br />
cDC.DrawState (CPoint (rcButton.left + ( bOver ? 4 : 3 ), rcButton.top + ( bOver ? 4 : 3 )), m_sizeImage, hIcon, DSS_MONO, CBrush (bOver ? (IS_INDETERMINATE(tbbutton) ? HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -20, 0) : HLS_TRANSFORM (::GetSysColor (COLOR_HIGHLIGHT), +50, -66)) : HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -27, 0)));<br />
DestroyIcon (hIcon);<br />
}<br />
if ( IS_ENABLED(tbbutton) )<br />
{<br />
::ImageList_Draw (m_hImageList, tbbutton.iBitmap, cDC.m_hDC,<br />
rcButton.left + ( (bOver && !bPressed) ? 2 : 3 ), rcButton.top + ( (bOver && !bPressed) ? 2 : 3 ), ILD_TRANSPARENT);<br />
}<br />
with
<br />
if ( !IS_ENABLED(tbbutton) || (bOver && !bPressed))<br />
{<br />
HICON hIcon = ImageList_ExtractIcon (NULL, (!IS_ENABLED(tbbutton)) ? m_hImageListGR : m_hImageListHT, tbbutton.iBitmap);<br />
cDC.DrawState (CPoint (rcButton.left + ( bOver ? 4 : 3 ), rcButton.top + ( bOver ? 4 : 3 )), m_sizeImage, hIcon, DSS_NORMAL,(CBrush*)NULL);<br />
DestroyIcon (hIcon);<br />
}<br />
else if ( IS_ENABLED(tbbutton) )<br />
{<br />
::ImageList_Draw (m_hImageListTC, tbbutton.iBitmap, cDC.m_hDC,<br />
rcButton.left + ( (bOver && !bPressed) ? 2 : 3 ), rcButton.top + ( (bOver && !bPressed) ? 2 : 3 ), ILD_TRANSPARENT);<br />
}<br />
That's it!
Greeting from Frank
|
|
|
|
|
When I run the demo on Windows 98 the menu bar items (File, Edit, etc.) are not highlighted as the mouse passes over them. Once you click on a menu to open it, everything is drawn correctly. This isn't a problem under Windows XP.
|
|
|
|
|
Indeed, this behavior is not available under Win98 and NT4. As these systems are now rather old, I do not project to implement it.
|
|
|
|
|
I like it~~ Thanks a lot
I am a student!
|
|
|
|
|
If run sdi-exe, he run minimized.
If run sdi(or mdi), then press preview, close preview. Appear small uncontrollable bar with undo & find.
|
|
|
|
|
It was an excellent article, mr. "Cought in the headlights" (your picture, i mean) , i'm definitely gonna use your code in my applications. I tried to write something like this long ago, but gave up in the end Instead, i wrote XP-Style menus which look like "Start" menu in Windows XP , when you can have two-three lines of text in just one menu item, and big beatiful icons 48x48;P. It's all here: www.tooltips.net
Thank you again for such excellent code
Cheers
Vitaly
|
|
|
|
|
When you're running WinXP with shadows enabled, you got two shadows, i'll see if i find a fix for this, but i think that it's easy to fix.
Good Work!!!!!!!!1
|
|
|
|
|
|
Easy to use , wonderful look and feeling.
tomPeakz
|
|
|
|
|
It integrated into my app very easy. and it has small footprint
Thanks
|
|
|
|
|
How can I change the color of the back ground of the menu?
|
|
|
|
|
I had trouble getting all levels of popups to be owner-drawn until I detached the HWND from the CMenu when attaching the popup, when the CMenu goes out of scope before calling TrackPopupMenu(). For example, this works:
CMenu subMenu;
(add to subMenu)
AppendMenu( MF_STRING | MF_POPUP, (UINT)subMenu.Detach(), title );
(subMenu goes out of scope before TrackPopupMenu is called on parent CMenu...)
and this does not:
AppendMenu( MF_STRING | MF_POPUP, (UINT)subMenu.m_hMenu, title );
Does anyone know if this approach leads to memory leaks? Probably eh? :> Silly standard menu doesn't complain about the second case at all, there must be some voodoo going on there... Guess I better add a CMenu std::vector...
Thanks again.
|
|
|
|
|
I just spent a whole day trying to get another implementation of owner-drawn menus up and running with our (granted, complex) existing menu code...
Finally gave up and switched to this. Dropped in the code as instructed, IN 1 MINUTE it was up, running, and looking GREAT! Thanks my man!
|
|
|
|
|
This project is awesome don't get me wrong, but I'm wondering...
the actual menu itself looks like menu, but the menu header ("File, Edit...etc") don't resemble an XP menu, I just noticed this as I was looking at Word 2002.
Just curious if this is something I am doing wrong or if it's hasn't been made yet.
|
|
|
|
|
The last version do it now !
|
|
|
|
|
This is really cool thanks, but I have one problem.
In my source code I disabled some menu items using the following code:
CMenu* pMenu = GetMenu();
m_bAutoMenuEnable=FALSE;
CMenu* subMenu = pMenu->GetSubMenu(4);
subMenu->EnableMenuItem(0, MF_GRAYED | MF_BYPOSITION);
DrawMenuBar();
It no longer works properly with your new class. How can I disable a menu item programically?
Thanks
Kevin Smith
|
|
|
|
|
I played around with the class to get the disabling working for me. Here's what I did.
Disclaimer: this may not be in line with what the author intended, and it may have
broken something else - but it works for me - I'm using VC 6.
1) I added a bDisabled param to CMenuItem::Draw() as follows:
void CMenuItem::Draw (CDC* pDC, LPCRECT pRect, bool bSelected, bool bDisabled) const
2) In CMenuXP::OnDrawItem(), I updated the call to item.Draw() to provide the param:
item.Draw(
&cDC,
&pDrawItemStruct->rcItem,
(pDrawItemStruct->itemState & ODS_SELECTED)!=0,
(pDrawItemStruct->itemState & ODS_DISABLED)!=0
);
3) I changed a lot of the GetDisabled() checks in void CMenuItem::Draw() to use the new bDisabled param.
Here's the whole new function.
///////////////////////////////////////////////////////////////////////////////
void CMenuItem::Draw (CDC* pDC, LPCRECT pRect, bool bSelected, bool bDisabled) const
{
COLORREF crBackImg = CLR_NONE;
if ( bSelected && !bDisabled )
{
COLORREF crHighLight = ::GetSysColor (COLOR_HIGHLIGHT);
CPenDC pen (*pDC, crHighLight);
// CBrushDC brush (*pDC, crBackImg = GetDisabled() ? HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +73, 0) : HLS_TRANSFORM (crHighLight, +70, -57));
CBrushDC brush (*pDC, crBackImg = HLS_TRANSFORM (crHighLight, +70, -57) );
pDC->Rectangle (pRect);
}
else
{
CRect rc (pRect);
rc.right = IMGWIDTH+IMGPADDING;
pDC->FillSolidRect (rc, crBackImg = HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +20, 0));
rc.left = rc.right;
rc.right = pRect->right;
pDC->FillSolidRect (rc, HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +75, 0));
}
if ( GetSeparator() )
{
CPenDC pen (*pDC, HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -18, 0));
pDC->MoveTo (pRect->left+IMGWIDTH+IMGPADDING+TEXTPADDING, (pRect->top+pRect->bottom)/2);
pDC->LineTo (pRect->right-1, (pRect->top+pRect->bottom)/2);
}
else
{
CRect rc (pRect);
CString sCaption;
if ( GetCaption (sCaption) > 0 )
{
// pDC->SetTextColor (GetDisabled() ? HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -18, 0) : ::GetSysColor (COLOR_MENUTEXT));
pDC->SetTextColor ( bDisabled ? HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -18, 0) : ::GetSysColor (COLOR_MENUTEXT));
pDC->SetBkMode (TRANSPARENT);
CBoldDC bold (*pDC, GetDefault());
rc.left = IMGWIDTH+IMGPADDING+TEXTPADDING;
pDC->DrawText (sCaption, rc, DT_SINGLELINE|DT_VCENTER|DT_LEFT);
CString sShortCut;
if ( GetShortCut (sShortCut) > 0 )
{
rc.right -= TEXTPADDING+4;
pDC->DrawText (sShortCut, rc, DT_SINGLELINE|DT_VCENTER|DT_RIGHT);
}
if ( GetChecked() )
{
COLORREF crHighLight = ::GetSysColor (COLOR_HIGHLIGHT);
CPenDC pen (*pDC, crHighLight);
CBrushDC brush (*pDC, crBackImg = GetDisabled() ? HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +73, 0) :
(bSelected ? HLS_TRANSFORM (crHighLight, +50, -50) : HLS_TRANSFORM (crHighLight, +70, -57)));
pDC->Rectangle (CRect (pRect->left+1, pRect->top+1, pRect->left+20, pRect->bottom-1));
}
if ( m_ImgDesc.m_hImgList != NULL && m_ImgDesc.m_nIndex != -1 )
{
bool bOver = !GetDisabled() && bSelected;
if ( GetDisabled() || (bSelected && !GetChecked()) )
{
HICON hIcon = ImageList_ExtractIcon (NULL, m_ImgDesc.m_hImgList, m_ImgDesc.m_nIndex);
pDC->DrawState (CPoint (pRect->left + ( bOver ? 4 : 3 ), rc.top + ( bOver ? 4 : 3 )),
CSize (IMGWIDTH, IMGHEIGHT), hIcon, DSS_MONO,
CBrush (bOver ? HLS_TRANSFORM (::GetSysColor (COLOR_HIGHLIGHT), +50, -66) : HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -27, 0)));
DestroyIcon (hIcon);
}
// if ( !GetDisabled() )
if ( !bDisabled )
{
::ImageList_Draw (m_ImgDesc.m_hImgList, m_ImgDesc.m_nIndex, pDC->m_hDC,
pRect->left+( (bSelected && !GetChecked()) ? 2 : 3 ), rc.top+( (bSelected && !GetChecked()) ? 2 : 3 ), ILD_TRANSPARENT);
}
}
else if ( GetChecked() )
{
// Draw the check mark
rc.left = pRect->left+5;
rc.right = rc.left + IMGWIDTH+IMGPADDING;
pDC->SetBkColor (crBackImg);
HBITMAP hBmp = LoadBitmap (NULL, MAKEINTRESOURCE(OBM_CHECK));
pDC->DrawState (CPoint (rc.left,rc.top+3), CSize(rc.Size()), hBmp, DSS_NORMAL, (HBRUSH)NULL);
DeleteObject (hBmp);
}
}
}
}
|
|
|
|
|
Thanks...
I should have replied earlier, that the author of the article wrote to me and informed me that using MF_GRAYED & MF_DISABLED instead of just MF_GRAYED flags should work. I tried his suggestion and it worked.
Thanks anyway.
|
|
|
|
|
Thank you very much, i have been looking for this grayed thing for quite some time now..;)
|
|
|
|
|
If other ownerdrawn controls coexist with your menus, CMenuXP will handle their OnOwnerDraw calls and assert if they're not menus.
Fix:
in CMenuXP.h:
...
void theClass::OnDrawItem (int i, LPDRAWITEMSTRUCT lpDrawItemStruct) \
{ \
if(lpDrawItemStruct->CtlType == ODT_MENU) \
CMenuXP::OnDrawItem (lpDrawItemStruct); \
else \
baseClass::OnDrawItem (i, lpDrawItemStruct); \
} \
...
Apart from that, it's a really great and easy-to-use class. Beau boulot!
Cheers, Marc Click to see my *real* signature
|
|
|
|
|