Owner Drawn Menus
Does anyone know any tutorials on the internet that cover Owner Drawn Controls, specifically Menus? if you are saying to yourself: "Why would anyone want an owner drawn menu?" well, i am trying to achieve the "Office XP Menu Style", i know how to draw the menu in the client window (using PatBlt()) but i cant find out how to draw ON the menu itself.
Don't know of any tutorials offhand, sorry. The basic idea however is this:
--Load or create your menu
--Set up a MENUITEMINFO structure so fMask = MIIM_TYPE, fType = MFT_OWNERDRAW and dwTypeData = whatever you feel like (usually a pointer to an application defined struc)
--Set the menu item(s) as owner drawn by calling SetMenuItemInfo.
--In your parent window proc, handle the WM_MEASUREITEM and WM_DRAWITEM messages. MSDN has good documentation on these items.
That's basically it.
office XP style? do you think that's how they did those? There is a shadow and such that I'm not sure you could simulate with an ownerdraw. I was assuming that they just made their own control rather than using actual menus. I'm probably wrong about that. I'd be curious to hear how it goes.
Don't like that solution? Here's another one, although far more involved and invites many bugs.
--Create 2 custom controls one for the menu bar and one for the popup menus.
--In each, handle all applicable mouse messages and painting. Make sure to install a timer to handle when your mouse moves in/out of the client area of your custom window otherwise if the mouse moves too fast you'll get items staying high-lighted
--Don't forget to leave room in the window for extra data -- you're probably gonna need a linked list to store all the menu items, and you'll wanna save the pointer to that list in GWL_USERDATA or similar
--You'll have to create the menu as a child of your app window. This'll mess up any drawing you were doing in the client area which you can fix either by using creating yet another window or drawing everything about 20 pixels lower.
Or, you could intercept WM_NCCALCSIZE, reserve yourself some area in the non-client area of the window, create the menu as a child of the desktop and try to coordinate the position and size of the menu bar with the position and size of your parent. Good luck with that one.
(and I'm pretty sure Office created their own control for this, as you mentioned)
Here is an example of the menu i want to copy (using the API, instead of MFC):
i tried to look at MSDN before, but i just dont understand what they are doing, thats why i was looking for a tutorial
Since your original post was about Owner Drawn Menus, here's some code regarding such to get you going. Sorry if it isn't the cleanest... just started C++ a couple of days ago... built it from DevC++ so there's the comments in there...
There's a cheap resource file, and a skeleton for the WM_DRAWITEM and WM_MEASUREITEM messages.
The basic idea is this: get the menu. Set the first item as owner-drawn. Then set it to 400 pixels wide. When DrawItem is called, draw a rectangle (green if selected) and then draw some text over top.
If you wanna add image lists or whatever later it's easy enough to do.
A simple resouce file...
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
char szClassName[ ] = "WindowsApp";
char szMenuString[ ] = "Some Text";
WinMain (HINSTANCE hThisInstance,
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = MAKEINTRESOURCE(1001); /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default color as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Windows App", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
544, /* The programs width */
375, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
/* Make the window visible on the screen */
ShowWindow (hwnd, nFunsterStil);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
/* Translate virtual-key messages into character messages */
/* Send message to WindowProcedure */
/* The program return-value is 0 - The value that PostQuitMessage() gave */
/* This function is called by the Windows function DispatchMessage() */
WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
switch (message) /* handle the messages */
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
selectedbrush = CreateSolidBrush(0xFF00);
hMenu = GetMenu(hwnd);
mii.cbSize = sizeof (MENUITEMINFO);
mii.fMask = MIIM_TYPE;
mii.fType = MFT_OWNERDRAW;
mii.dwTypeData = szMenuString;
lpmis = (LPMEASUREITEMSTRUCT) lParam;
lpmis->itemWidth = 200;
lpmis->itemHeight = 20;
lpdis = (LPDRAWITEMSTRUCT) lParam;
bgbrush = (HBRUSH) GetStockObject(WHITE_BRUSH);
if (lpdis->itemState == ODS_SELECTED) bgbrush = selectedbrush;
lpdis->rcItem.left += 2;
lpdis->rcItem.top += 2;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
#define IDM_FILE_EXIT 106
#define IDM_APPMENU 1001
Thanks everyone, i figured it all out :)
now i am trying to make a custom drawn toolbar to complete my WIndows XP menus :-D
http://okiesmokiezz.cjb.net/ <- screenshots of my progress