http://www.developer.com/net/cplus/article.php/3501601/Owner-Draw-Menus-with-NET-and-Managed-C.htm
While my main forte is low-level programming, I've always enjoyed writing owner-draw and custom-draw controls. When you think about it, there's a lot of philosophical similarity between the two. When writing a device driver, you're writing at a level that is not very well documented and at first appears very foreboding. While not nearly as difficult, taking over the drawing for a control is much the same in terms of doing something that at first glance appears to be quite difficult when actually it's notespecially with .NET. This week's column illustrates just how easy it is to owner-draw a menu item using .NET and Managed C++.
First, it presents the steps for creating an owner-draw menu and shows how to implement those in your application. The second section then shows you how to use the simple, yet effective, owner-draw menu class that accompanies the article. That way, if you're in a hurry, you can simply plug the class into your application now and go back and read the code at your leisure.
If you build and run the application, you should see results similar to those shown in
Figure 1.
Tom Archer owns his own training company, Archer Consulting Group, which specializes in educating and mentoring .NET programmers and providing project management consulting. If you would like to find out how the Archer Consulting Group can help you reduce development costs, get your software to market faster, and increase product revenue, contact Tom through his Web site.
Owner-Draw Menus with .NET and Managed C++
April 29, 2005
Creating an Owner-Draw Menu
The following steps demonstrate how to create a File Exit menu using the Comic Sans MS font. As I dislike when an author assumes the state of my code, I'll start with creating the application. Obviously, if you're past that point, you can skip past the first couple of steps:
MenuItem* menuFile = new MenuItem(S"&File");
mainMenu1->MenuItems->Add(menuFile);
MenuItem* menuExit = new MenuItem(S"E&xit");
menuFile->MenuItems->Add(menuExit);
protected: void MenuMeasureItem(Object* sender, MeasureItemEventArgs* args)
{
// Retrieve the MenuItem object
MenuItem* item = static_cast<MenuItem*>(sender);
// Create the font object for the menu item
System::Drawing::Font* font =
new System::Drawing::Font(S"Comic Sans MS", 16);
// Retrieve the size of the menu item text
SizeF siF = args->Graphics->MeasureString(item->Text, font);
// Set the menu item's size based on the size needed for the text
args->ItemWidth = Convert::ToInt32(Math::Ceiling(siF.Width));
args->ItemHeight = Convert::ToInt32(Math::Ceiling(siF.Height));
}
protected: void MenuDrawItem(Object* sender, DrawItemEventArgs* args)
{
// Retrieve the MenuItem object
MenuItem* item = static_cast<MenuItem*>(sender);
// Create a Font object
System::Drawing::Font* font =
new System::Drawing::Font(S"Comic Sans MS", 16);
// Draw the background
Rectangle recText = args->Bounds;
args->DrawBackground();
// Create a brush depending on if the user
// has selected the item
Brush* brush;
if ((args->State & DrawItemState::Selected) != 0)
brush = SystemBrushes::HighlightText;
else
brush = SystemBrushes::FromSystemColor(SystemColors::MenuText);
// Tell .NET that we want to display the mnemonic (underlined
// character in the menu text) if one is present
StringFormat* format = new StringFormat();
format->HotkeyPrefix =
System::Drawing::Text::HotkeyPrefix::Show;
// Draw the menu
Graphics* g = args->Graphics;
g->DrawString(item->Text,
font,
brush,
Convert::ToDouble(recText.Left),
recText.Top,
format);
}
menuExit->MeasureItem +=
new MeasureItemEventHandler(this, MenuMeasureItem);
menuExit->DrawItem +=
new DrawItemEventHandler(this, MenuDrawItem);
private: void OnExit(Object* sender, EventArgs* e)
{
this->Close();
}
menuExit->Click += onClick;

Figure 1. Owner-Draw File Exit Menu
Putting Everything into a Class
Now, condense everything into a more usable C++ class called ACG::MenuItem. Instead of redisplaying the same code already presented in the previous section, this section shows you only how to use the example class:
// Instantiate the top level menu
MenuItem* menuFile = new MenuItem(S"&File");
mainMenu1->MenuItems->Add(menuFile);
// Instantiate the owner-draw menu, specifying the
// "click" event handler, font, and font's point size
ACG::MenuItem* menuExit =
new ACG::MenuItem(S"E&xit",
new EventHandler(this, ExitClick),
S"Comic Sans MS",
16);
menuFile->MenuItems->Add(menuExit);
private: void ExitClick(Object* sender, EventArgs* e)
{
this->Close();
}
Download the Code
To download the code for the demo application, click here.
About the Author