|
Overall I would say this is excellent, and is easy to integrate
Four suggestions for improvements (or questions):
1. What about the system menu?
2. What about handling if the toolbar is (slightly) not standard size? Maybe there could be a function to pass a menu-only toolbar bitmap with normal sized buttons to the menu code, even if the app's actual toolbar is not the standard button size.
3. Radio marks on menus show as checks, not dots
4. Is there a way to use the same underlying code to use on popup menus? (you know ones we create with TrackPopupMenu when a user right clicks on an item or something)
|
|
|
|
|
For the 4th point, it should work in the demo !?!
|
|
|
|
|
Thanks
I just stuck a copy of your code (without even looking at the sample) in 2 programs I had handy to see if it worked. These both have multiple popups and it didn't work on any of these popups. They just came up as normal popups.
I took a look at your sample, and yes it works on that.
There are 2 differences I think in the 2 programs I tried it on:
1. Build their popup menus on the fly, using AppendMenu etc
2. TPM_RETURNCMD in the popup code.
I haven't yet tested this out at all, and may not for some time, but my guess is TPM_RETURNCMD is the problem.
To be fair this is not really a weakness of your code, but it does mean it's not quite a drop in replacement.
|
|
|
|
|
Look at the 4th parameter of the TrackPopupMenu call:
pPopup->TrackPopupMenu (TPM_RIGHTBUTTON, pt.x, pt.y, GetParentFrame()); In my demo, this is the frame.
The window passed as 4th parameter must handle the MENUXP macros: ON_MENUXP_MESSAGES, DECLARE_MENUXP and IMPLEMENT_MENUXP.
Add them in your programs and it should work !
Bye
|
|
|
|
|
I did already and it didn't make a difference.
The problem seems to be the TrackPopupMenu call had TPM_NONOTIFY flag set
Removing this flag fixes the problem with display (tried on only 1 menu so far). However this then causes a knock on problem as the menu items are now all disabled, presumably because there is no code to handle the pCmdUI->Enable(...) etc stuff for these items.
So I know how to fix it in that program, but unless there is a trick I'm not aware of, it would be a fairly major job as it requires turning the code around: instead of building a popup with the right items enabled/disabled, I think that I would need to move move the enable/disable logic into separate handlers, and decide about each menu item, after the menu has been built rather than before.
|
|
|
|
|
a little impovement for MDI with multiple documents:
Change CMenuXP class in:
class CMenuXP : public CMenu
{
// Attributes
public:
static CMap <int, int, CString, CString&> m_sCaptions;
static CMap <int, int, CImgDesc, CImgDesc&> m_Images;
// Operations
public:
static void SetWinXPStyle (HMENU hMenu, CWnd* pWnd = NULL);
static bool IsOwnerDrawn (HMENU hMenu);
static void OnMeasureItem (MEASUREITEMSTRUCT* pMeasureItemStruct);
static void OnDrawItem (DRAWITEMSTRUCT* pDrawItemStruct);
static LRESULT OnMenuChar (HMENU hMenu, UINT nChar, UINT nFlags);
protected:
//
// new code !
//
static CImageList m_ImageList;
//
static int AddImage(HIMAGELIST hSourceImgList,int sourceImageIndex);
//
// end new code...
//
};
add in menuxp.cpp
CMap <int, int, CString, CString&> CMenuXP::m_sCaptions;
CMap <int, int, CImgDesc, CImgDesc&> CMenuXP::m_Images;
CImageList CMenuXP::m_ImageList; // new initialization
int CMenuXP::AddImage(HIMAGELIST hSourceImgList,int sourceImageIndex)
{
int index=-1;
//
if( hSourceImgList && sourceImageIndex > -1 ){
HICON hIcon = ::ImageList_ExtractIcon(
NULL ,
hSourceImgList ,
sourceImageIndex );
if( hIcon ){
//
if( CMenuXP::m_ImageList.m_hImageList == NULL )
CMenuXP::m_ImageList.Create(16 , // cx,
16 , // cy,
ILC_MASK , // nFlags,
0 , // int nInitial,
16 ); // grow...
//
if( CMenuXP::m_ImageList.m_hImageList != NULL ){
index=m_ImageList.GetImageCount();
CMenuXP::m_ImageList.Add(hIcon);
}
::DestroyIcon(hIcon);
}
}
return index;
}
and in the function SetWinXPStyle sostitute:
//
//----------- Previus code:
//
// CImgDesc imgDesc (
// (HIMAGELIST)pBar->SendMessage (TB_GETIMAGELIST, 0, 0), tbbi.iImage);
// m_Images.SetAt (mii.wID, imgDesc);
//
// ---------- New code...
//
if( (nMyImageIndex=AddImage(
(HIMAGELIST)pBar->SendMessage(TB_GETIMAGELIST, 0, 0),
tbbi.iImage)) > -1 ){
CImgDesc imgDesc(CMenuXP::m_ImageList.m_hImageList,nMyImageIndex);
m_Images.SetAt( mii.wID, imgDesc );
}
break;
In this way if you destroy some toolbars etc.. at runtime the image is correct..
Sorry for my poor english and thanks for your job
|
|
|
|
|
Hello!
This class is really cool and so easy to use! But there's one thing I'm missing. The original office xp menus have this blue border if you move your mouse over the menu. This class (http://www.codeproject.com/menu/shadowmenu.asp) has that effect.
I would be really gratefull if you could include this feature.
Bye,
Gertschi
|
|
|
|
|
|
I'm using 32x32 icons in my toolbar, and they appear in the same size in Menu. How can I fix it? I want them in smaller size.
|
|
|
|
|
Try that:
....
if ( m_ImgDesc.m_hImgList != NULL && m_ImgDesc.m_nIndex != -1 )
{
bool bOver = !GetDisabled() && bSelected;
bool bDontUseImage = FALSE;
int cx, cy;
if(ImageList_GetIconSize(m_ImgDesc.m_hImgList, &cx, &cy))
{
bDontUseImage = (cy > IMGHEIGHT) || (cx > IMGWIDTH);
}
if(!bDontUseImage) // we have small Icons in Image list => do it faster and cleaner
{
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() )
{
::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
{
HICON hIcon = ImageList_ExtractIcon (NULL, m_ImgDesc.m_hImgList, m_ImgDesc.m_nIndex);
if ( GetDisabled() || (bSelected && !GetChecked()) )
{
DrawIconEx( pDC->m_hDC,
pRect->left + ( bOver ? 4 : 3 ),
rc.top + ( bOver ? 4 : 3 ),
hIcon,
16, 16,
0,
NULL,
DI_NORMAL );
}
if ( !GetDisabled() )
{
DrawIconEx( pDC->m_hDC,
pRect->left+( (bSelected && !GetChecked()) ? 2 : 3 ),
rc.top+( (bSelected && !GetChecked()) ? 2 : 3 ),
hIcon,
16, 16,
0,
NULL,
DI_NORMAL );
}
DestroyIcon (hIcon);
}
}
....
|
|
|
|
|
That's right, but, in order to avoid image stretching another posibility is to change the size of the displayed images to match those from the toolbar. This can be done easily modifying the function:
static void SetWinXPStyle (HMENU hMenu, CWnd* pWnd = NULL);
To:
static void SetWinXPStyle (HMENU hMenu, CWnd* pWnd = NULL, imgWidth = 16, int imgHeight = 16);
Then, declare two additional static members and initialize them inside SetWinXPStyle:
// Attributes
public:
static CMap <int, int, CString, CString&> m_sCaptions;
static CMap <int, int, CImgDesc, CImgDesc&> m_Images;
static int m_imgWidth; // <-- new one
static int m_imgHeight; // <-- new one
void CMenuXP::SetWinXPStyle (HMENU hMenu, CWnd* pWnd, int imgWidth /*16*/, int imgHeight /*16*/)
{
m_imgWidth = imgWidth;
m_imgHeight = imgHeight;
// etc...
}
After it, delete IMGWIDTH/IMGHEIGHT definitions in CPP file and replace it by CMenuXP::m_imgWidth/m_imgHeight. Finally, in your CMainFrm::OnCreate (or wherever you initialize the menu) call CMenuXP::SetWinXPStyle() with the appropiate width/height of the buttons.
Perhaps 32x32 buttons cause a excessively height menu items, but in 21x20 buttons (my case) it looks fine, very much better than stretching them.
Eduard Huguet (eduard@cibercat.es)
Cibercat SL
|
|
|
|
|
This is surely a awesome work .
what I want to know is that is it possible to draw in Menu bar area als0 ??
that is can I give it a look some what similar to OfficeXp products ??
I know if we implement it as toolbar instead of menubar then we can do that ..
but you get my question ??
Regards,
Abhishek Narula
"Learn to appreciate others ... World would appreciate you"
|
|
|
|
|
This is harder than it first appears. While Windows does allow a programmer to create custom-drawn menus, the bar itself cannot be changed. The menu bar is considered to be a part of the non-client area. A simple test is to start the Windows Notepad, and then use Spy++ to observe what windows are available for selection.
Menus are not created through the "CreateWindow" and "CreateWindowEx" API functions. Rather, there is a separate "CreateMenu" function, specifically for this purpose.
The simplest solution to the problem is create the menu in a toolbar control, where you can use owner-draw code across the entire control. If you do not want to use a toolbar control at all, you would have to implement a menu system from scratch, and then figure out how to attach it to the main window in a way that would keep it out of the client area, and be relatively transparent to the application, unless you don't mind handling custom messages.
--
Paul
"I drank... WHAT?"
|
|
|
|
|
|
This new version is more robust and easier to use.
Have fun with it !
|
|
|
|
|
|
|
And when are we gonna see it?
|
|
|
|
|
|
This doesn't work at all if you dissect the project.
Try taking MenuXP.cpp/.h and doing anything with it ... the class is not standalone. I tried grabbing all the classes from the Tools directory, but there are classes defined within the UI code that are required. There is no flexibility built into your code ... outside of your test app it is unusable.
I look forward to seeing your next version. Keep at it, this could be really good ...
Jase
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
View your digital photos and images with ease using the ultimate desktop image manager for Microsoft Windows
Download your free copy of SlideShow Desktop today from http://www.slideshowdesktop.com
|
|
|
|
|
Well, i just got the Visual Studio .NET Enterprise and when i tried to load the project i got an error showing the file menu, all the others are showed very good, your project is good, but that error says a lot of the CMenuXP class.
|
|
|
|
|
Your MenuXp Class is a greet work, thx
but I have a bug with, when I have a menu with all of their item as submenu, the text of the submenu will not appears, I have just the arrow
Ps : excuse for my english, i am french
Sephiroth:
Carpentier Armand
|
|
|
|
|
I am apparently solve the problem
the bug come from the WM_MEASUREITEM message not traited for submenu
I am using this way to solve it, but I am not sure it's the best way
i am add on CMenuXp::OnMeasureItem the call to CMenuXp::MeasureItem()
void CMenuXP::OnMeasureItem (MEASUREITEMSTRUCT* pMeasureItemStruct)
{
if ( pMeasureItemStruct->CtlType == ODT_MENU && ::IsMenu ((HMENU)pMeasureItemStruct->itemID) )
{
pMeasureItemStruct->itemHeight = max (20, pMeasureItemStruct->itemHeight);
MeasureItem(pMeasureItemStruct); <== Add ligne
}
}
and remove the static of CMenuXP::OnMeasureItem
static void OnMeasureItem (MEASUREITEMSTRUCT* pMeasureItemStruct);
to => void OnMeasureItem (MEASUREITEMSTRUCT* pMeasureItemStruct);
in my CMainFrame, I call the CMenuXP::OnMeasureItem by the global var _gtxMenuXP
void CMainFrame::OnMeasureItem (int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
CFrameWnd::OnMeasureItem (nIDCtl, lpMeasureItemStruct);
_gtxMenuXP.OnMeasureItem (lpMeasureItemStruct); <= ligne modified
}
Sephiroth:
Carpentier Armand
|
|
|
|
|
The underline of a character (for example on the 'F' of the file menu) dissappears. It do show up again when selecting something in the menu by mouse or Alt-key. Or is that just me?
|
|
|
|
|
Great job!but there is a bug in "File" menu!
firstly, i click one of the root menu such as "File", "Edit", "View"
then the menu popup , and i keep moving the mouse between these root menu,
when i move the mouse quickly over the menu and stop over the "File" menu at
last ,the text on the File menu disappear. and only "File" menu got this
problem .
let's talk about code ^6^
|
|
|
|
|