Title: Make owner drawn menus in C#
It's easiest to use menus with the default appearance, but you can make owner drawn menus if you want. It's not hard, but you need to follow several steps.
First, at design time, set the MenuItem control's OwnerDraw property to true. Then at run time, you must respond to two events for the menu: MeasureItem and DrawItem.
The MeasureItem event handler receives as a parameter an object of type MeasureItemEventArgs. The code must set this object's ItemHeight and ItemWidth properties to tell the program how much room the menu item needs.
This example uses the following code to determine how big the string it will draw is going to be. It then requests enough room for the string.
private const string FONT_NAME = "Times New Roman";
private const float FONT_SIZE = 12;
private const FontStyle FONT_STYLE = FontStyle.Bold;
private const string MENU_CAPTION = "Say Hi";
// Tell Windows how big to make the menu item.
private void mnuFileSayHi_MeasureItem(
object sender, MeasureItemEventArgs e)
{
// Create the font we will use to draw the text.
using (Font menu_font = new Font(
FONT_NAME, FONT_SIZE, FONT_STYLE))
{
// See how big the text will be.
SizeF text_size =
e.Graphics.MeasureString(MENU_CAPTION, menu_font);
// Set the necessary size.
e.ItemHeight = (int)text_size.Height;
e.ItemWidth = (int)text_size.Width;
}
}
This code starts with some constants that define the font that the program will use to draw the menu item. The MeasureItem event handler creates the font and uses e.Graphics.MeasureString to find out how much space the text needs in that font. It then sets e.ItemHeight and e.ItemWidth appropriately.
The DrawItem event handler receives as a parameter an object of type DrawItemEventArgs that has properties and methods that let you draw the menu item. The following code shows the example program's DrawItem event handler.
// Draw the menu item.
private void mnuFileSayHi_DrawItem(
object sender, DrawItemEventArgs e)
{
// Create the font we will use to draw the text.
using (Font menu_font = new Font(
FONT_NAME, FONT_SIZE, FONT_STYLE))
{
// See if the mouse is over the menu item.
if ((e.State & DrawItemState.Selected)
!= DrawItemState.None)
{
// The mouse is over the item.
// Draw a shaded background.
using (Brush menu_brush =
new LinearGradientBrush(
e.Bounds, Color.Red,Color.Black,90))
{
e.Graphics.FillRectangle(menu_brush, e.Bounds);
}
// Draw the text.
e.Graphics.DrawString(MENU_CAPTION, menu_font,
System.Drawing.Brushes.AliceBlue,
e.Bounds.X, e.Bounds.Y);
}
else
{
// The mouse is not over the item.
// Erase the background.
e.Graphics.FillRectangle(
System.Drawing.Brushes.LightGray,
e.Bounds.X, e.Bounds.Y,
e.Bounds.Width, e.Bounds.Height);
// Draw the text.
e.Graphics.DrawString(MENU_CAPTION, menu_font,
System.Drawing.Brushes.Black,
e.Bounds.X, e.Bounds.Y);
}
}
}
The event handler creates the font and then checks e.State to see if the mouse is over the menu item. If it is, the program draws a gradient background and the menu's text in AliceBlue. If the mouse is not over the menu item, the program draws a simple light gray background with black text.
This example simply draws text with a background, but you could draw images, shapes, or anything else you want the menu item to display.
The value e.State can indicate other properties of the menu item. For example, it can tell you if the item is disabled, checked, or in its default visual state. You can change the way you draw the item accordingly if you like.
The program can catch the menu item's Click event handler as usual. This example simply displays a message box when you select the Say Hi menu item.
Download the example to experiment with it and to see additional details.
|