NewMenu
The NewMenu is published on
CodeProject. There you will find the discussion board.
This is a prerelease of NewMenu 1.13 (will be published shortly)
Download executable
Samples - 731 Kb
Download demo projects for visual
studio 6.0/7.0 - 282 Kb
Download source NewMenu - 52 Kb
Released NewMenu 1.11 (Published on codeproject)
Download executable Samples
- 671 Kb
Download demo projects for visual
studio 6.0/7.0 - 291 Kb
Download source NewMenu - 56 Kb
STYLE_XP | STYLE_ICY | STYLE_ORIGINAL |
Introduction
This class, CNewMenu
, implements owner drawn menus derived
from the CMenu
class. The coal of this class is to have menus with
the same look as the new menu from the Microsoft products. In the other hand an
easy use of a new menu class with Icons
and Title
support.
I was inspired from the great class BCMenu from Brent Corkum. I took some ideas
and almost every function, but reimplemented almost the whole code and expanded
it with some other nice functions. It was a hard work to change the look of the
whole menu that belongs to an application, changing border and adding shading
.
Furthermore, it was tricky changing all menus under windows 2000 or system menu
under Windows XP when you are using themes. Over all, I hope it's now easy
enough for you to use this class in new applications.
This new menu works under Windows 95/98/Me and Windows NT4.0/2000/XP. When you
like to use Chinese or some other special characters, you have to compile your
project with Unicode. But keep in mind you must have installed the Unicode
libraries with the Visual studio otherwise you get a linking error.
Additional when you want that your program works on all platforms, you have to
compile it with the Visual Studio 6.0. I did not find out why the drawing don't
work fine when it is compiled with the Visual Studio 7.0 under Windows NT 4.0.
Furthermore when you do not like the flat border you can use the
STYLE_XXX_NOBORDER and then menus will have the standard menu border from the
system.
Nice Title in Menus
Oh yes, its also possible to add a title to menu. You can add a title on the
top or on the left side of a menu. You can have a gradient or a solid color as
background. With the function
SetMenuTitle
you can add or remove a title from a menu. The gradient drawing works also on Windows 95.
// Set a title to the system menu
m_SystemNewMenu.SetMenuTitle(_T("New Menu Sample"),
MFT_GRADIENT|MFT_LINE|MFT_CENTER);
New icons effects brightening, glooming and graying
Under menu style XP you have the possibility to enable or disable the additional drawing style to icons. Disabled icons become a grayed look and non selected icons become a gloom look. You can see the different between those drawing styles in the sample. |
How to use the CNewMenu in a project
The easiest way is to replace allCDialog, CFrameWnd, CMDIFrameWnd,
and
CMDIChildWnd, CMiniFrameWndCMultiDocTemplate
through
the new classesCNewDialog, CNewFrameWnd,
CNewMDIFrameWnd, CNewMDIChildWnd, CNewMiniFrameWnd
andCNewMultiDocTemplate
in your project.
Set in the application, derived fromCWinApp
, the menustyle just
before you create the frame or a dialog window in the functionInitInstance
.
// Set drawing style of all menus to XP-Mode or STYLE_ORIGINAL
CNewMenu::SetMenuDrawMode(CNewMenu::STYLE_XP);
When you have a multi document template, add the loading code for menu icons
just after creating the template.
CNewMultiDocTemplate* pDocTemplate;
pDocTemplate = new CNewMultiDocTemplate(IDR_MDINEWTYPE,
RUNTIME_CLASS(CMDINewMenuDoc),
// custom MDI child frame
RUNTIME_CLASS(CChildFrame),
RUNTIME_CLASS(CMDINewMenuView));
AddDocTemplate(pDocTemplate);
// Loading toolbar icons into the menu
pDocTemplate->m_NewMenuShared.LoadToolBar(IDR_DRAWBAR);
Insert at the end of OnCreate function of the MainFrame the loading code for
the icons. For example:
m_DefaultNewMenu.LoadToolBar(IDR_MAINFRAME);
Finally don't forget to include the definition from the "NewMenu.h" in stdafx.h
and add NewMenu.cpp to the project.
Now you are ready to use the class.
How to use the CNewMenu in a dialog-Application
Set in the application the menustyle before you create the dialog in the
function InitInstance.
// Set drawing style of all menus to XP-Mode
CNewMenu::SetMenuDrawMode(CNewMenu::STYLE_XP);
Replace allCDialog
toCNewDialog
in your Project.
For example base class fromCAboutDlg
.
For loading bitmaps in to the menu the best place is inOnInitDialog
function after calling the base class function.
// CDialogDlg could be your Dialog.
BOOL CDialogDlg::OnInitDialog()
{
// Call the baseclass
CNewDialog::OnInitDialog();
// Load icons to the menu
m_DefaultNewMenu.LoadToolBar(IDR_MAINFRAME);
}
Don't forget to include the the definition from the "NewMenu.h" in stdafx.h and
add NewMenu.cpp to the project.
How to use the CNewMenu in a special frame window
Normally you should overwritemeasureitem
,menuchar
and
initmenupopup
. For this purpose I use theCNewFrame
template
class. So you can replace 'CYourSpecialBase
' with 'CNewFrame
'
in your project.
But don't change it inIMPLEMENT_DYNAMIC
,IMPLEMENT_SERIAL
orIMPLEMENT_DYNACREATE
the base class to the new one.
IMPLEMENT_DYNAMIC(CYourNewSpecialFrame, CYourSpecialBase)
Don't forget to change the baseclass in BEGIN_MESSAGE_MAP.
BEGIN_MESSAGE_MAP(CYourNewSpecialFrame, CNewFrame
)
//{{AFX_MSG_MAP(CYourNewSpecialFrame)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
For loading bitmaps in to the menu, you can add the code inOnCreate
function.
Finally don't forget to include the the definition from the "NewMenu.h" in
stdafx.h and add NewMenu.cpp to the project.
How to use the CNewMenu in a MDI-Application
Change in the the application class in theBOOL InitInstance()
function
theCMultiDocTemplate
toCNewMultiDocTemplate
CNewMultiDocTemplate* pDocTemplate;
pDocTemplate = new CNewMultiDocTemplate(IDR_MDINEWTYPE,
RUNTIME_CLASS(CMDINewMenuDoc),
// custom MDI child frame
RUNTIME_CLASS(CChildFrame),
RUNTIME_CLASS(CMDINewMenuView));
AddDocTemplate(pDocTemplate);
Now insert the following code for loading additional bitmaps from a toolbar
into the menus.
// Loading toolbar icons into the menu
pDocTemplate->m_NewMenuShared.LoadToolBar(IDR_DRAWBAR);
// Set drawing style of all menus to XP-Mode
CNewMenu::SetMenuDrawMode(CNewMenu::STYLE_XP);
Change the base class from the main frame class (CMainFrame
) from
to
CMDIFrameWndCNewMDIFrame
in definition and
implementation file.
// Change the base class in the following makro
IMPLEMENT_DYNAMIC(CMainFrame, CNewMDIFrameWnd)
// don't forget to change here the baseclass
BEGIN_MESSAGE_MAP(CMainFrame, CNewMDIFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code !
ON_WM_CREATE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
Add at the end ofint CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
for loading bitmap in the default menu.
m_DefaultNewMenu.LoadToolBar(IDR_MAINFRAME);
Finally change the baseclass of the child frame fromCMDIChildWnd
to
CNewMDIChildWnd
. Do the same for all derived classCDialog
to the base class ofCNewDialog
.
Don't forget to include the the definition from the "NewMenu.h" in stdafx.h and
add NewMenu.cpp to the project.
How to use the CNewMenu in a SDI-Application
Set in the application the menustyle before you create the dialog in the
functionInitInstance
.
// Set drawing style of all menus to XP-Mode
CNewMenu::SetMenuDrawMode(CNewMenu::STYLE_XP);
Replace all CDialog toCNewDialog
in your Project.
Change the base class from the main frame class (CMainFrame
) from
to
CFrameWndCNewFrameWnd
in definition and implementation file.
Add at the end ofint CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
for loading bitmap in the default menu.
m_DefaultNewMenu.LoadToolBar(IDR_MAINFRAME);
Don't forget to include the the definition from the "NewMenu.h" in stdafx.h and
add NewMenu.cpp to the project.
How to replace system menu in system dialogs
Sometimes it would be pretty to change the menu in MessageBox or in
CFileDialog too. But unfortunately a MessageBox has no base class for
owerwriting. An other problem has the file dialog, there are at least two
dialog and the CFileDialog does only subclass the child dialog of the shown
FileDialog. For those dialog, and some more, I added a special subclassing
mechanism for our work.
// Subclass dialog with system menu
CNewMenuHelper myHelper(NEW_MENU_DIALOG_SUBCLASS|NEW_MENU_DIALOG_SYSTEM_MENU);
AfxMessageBox(_T("You must restart the application"),MB_OK);
Even thought what can I do when I do not want to have a menu border
replacing in the next shown dialog? It is very simple! Just place the
CNewMenuHelper before your call like in the following sample.
// Subclass dialog with normal border painting
CNewMenuHelper myHelper(NEW_MENU_DEFAULT_BORDER);
AfxMessageBox(_T("You must restart the application"),MB_OK);
Color replacing of bitmaps with 16 colors
The MFC replace some colors depended of the chosen system colors. So when you
use a black line in the bitmap, the color black will be replaced with the
system color of COLOR_BTNTEXT
. Following the color mapping map. By
the way, it is the same color mapping of the toolbars.
The color RGB(0x00,0x00,0x00) will be changed to COLOR_BTNTEXT // black
The color RGB(0x80,0x80,0x80) will be changed to COLOR_BTNSHADOW // dark gray
The color RGB(0xC0,0xC0,0xC0) will be changed to COLOR_BTNFACE // bright gray
The color RGB(0xFF,0xFF,0xFF) will be changed to COLOR_BTNHIGHLIGHT // white
Adding Icons to Menus
There are several possibilities adding icons to menu. An easy way is with a
toolbar resource. But the developer studio support only 16 color for
toolbar-bitmaps. What you can do is: first define your toolbar; then replace
the saved toolbar-bitmap with a hicolor bitmap by hand. Additional you can
define every icon in a different bitmap and assign it to a menuitem. My way was
define a bitmap like in an image list, make a helper table with the resource id
of the bitmap, size of an icon and followed by the ids of the icons. The end of
the table must be marked with an id number NULL.
// Define the table
static WORD ToolId[] =
{ IDR_NEWMENU256, // Resource id of the bitmap-icons
16, 15, // Dimension of each icon
ID_FILE_NEW, // First icon's ID
ID_FILE_OPEN, // Second icon's ID
ID_FILE_SAVE, // and so on...
NULL}; // Marker for end of table
//Load the definition into menu with transparent color
m_DefaultNewMenu.LoadToolBar(ToolId,RGB(192,192,192));
How to add an icon to a submenu
It is very simple to add or change the title of a submenu entry when you know
the menu text. The helper function ModifyODMenu
can be used.
// set the icon IDB_MORE_C to the submenu "More A"
m_NewMenuShared.ModifyODMenu(0,_T("More A"),IDB_MORE_C);
Menu under Windows 2000
It was a strange thing to detect, that under Windows 2000, you have a window
menu with handle 0x10012, which is shared to all application. (I think under
Windows 98 is the menu 0x0090). I don't know why, but this is also a reason of
the specialty for some effects belonging to subclassing menu. First when you
have disabled menu effects, the menu windows are alternating created or showed.
That means, first showed menu is mostly the special menu, never created nor
destroyed only showed and disabled, and the second is normal created and
destroyed after closing. The third time, sometime, the special window is showed
again and then the next menu is created normal. For this reason, when you
subclass the special menu, you are responsible to restore all values before
unsubclassing it. Be careful when you changing some flags or styles, because
the other applications like having the standard menu. You can also receive
bluescreen when you forget to unsubclass or when changing painting areas
belongs to that menu. Really ugly!!! Second, when you enabled menu effects
every shown menu is created new from scratch. For this reason it doesn't matter
when you don't restore all flags or styles!
But almost I forgot to explain how I got the goal to subclass all menus. Well,
for first, you can't subclass the system menu class #32768 from an application;
also I was looking for other possibility. I decide to create a windows hook for
all windows messages and catching all messages for creating a window. After
checking for the window class, when I found the menu class, I subclassed it.
But, how I can subclass the special menu, which is never created? I found, that
one of the first messages, which were sending to that menu, was 0x01E2 and one
of the latest WM_SHOWWINDOW
. So I caught these messages for sub-
and unsubclassing the special menu. Only between those two messages you have
access to the special window!! Why? I don't know, but be careful.
How to paint the border
Well after I got it to subclass the menu window I can draw the border by
myself by processing WM_NCPAINT
message. But how is the shade
made? Just before the menu is showed on the screen I save the menu region in a
bitmap, this is a reason why it does not work when the underground has been
changed, and combine it with a shade drawing. An other way would be using
layered windows, but this will not work on all systems like windows 95/98.
System menu under Windows XP
I thought owner drawing a menu is all time easy. But on Windows XP, with
themes enabled, it is a curious thing. Especially the main frame when the
system menu were displayed. Instead of owner drawing, the menu items were drawn
by the frame. The frame had painted the windows button of the width of the menu
at the place of the menu item :-) instead of drawing it. Strange! So I found a
workaround. I increased the menu items identifier before showing the menu and
restored after closing it. So, it works under Windows 2000 and XP.
Important info for debugging the new menu under Windows 2000
You should never stop debugging when you are in middle painting of the menus,
because the special menu wouldn't be restored nor unsubclassed. Furthermore
there were a lot of strange effects. It is not forbidden, but be careful and
have a lot time for rebooting the system when it doesn't work correctly after
stopping the debugger.
History
23 January 2003 - Version 1.13
SetMenuText fixed.
Menubar color with theme fixed.
Added some helper for borderhandling of non CNewMenu
10 November 2002 - Version 1.11
Border drawing with menu animation under Win 98 corrected.
Border drawing / repainting when submenu closed fixed.
New menu style ICY.
Helperclasses for changing system menu for CommonDialog.
30 July 2002 - Version 1.10
Sharing Icons between menu for saving GDI-Resources.
New effects for drawing icons under STYLE_XPxx.
Recoloring of menu icons by changing system colors.
Drawing of the scroll button by extreme big menus a little bit better.
Mixing different icon sizes in a menu is now supported but they are not zoomed
to the same size.
Known bugs
Menu border with shade is not updated when underground has been changed.
Menu border is drawn in a wrong size after changing the menu border style under
windows settings. But restart the application and then it will work again fine.
The High Contrast Mode is not supported with all right colors.
<출처>
http://www.podetti.com/NewMenu/
'Dev > C, C++' 카테고리의 다른 글
전체경로를 받아 파일이름을 제외한 경로만 구하기 (0) | 2003.07.18 |
---|---|
CTreeCtrl에서 ItemData 찾기 (자식노드 포함) (1) | 2003.07.18 |
MFC에서 타이틀 변경은 어떻게 하나요? (1) | 2003.02.06 |
MFC용 ADO클래스 (0) | 2003.02.06 |
Http프로토콜을 이용한 파일 다운로드 (0) | 2003.01.23 |