|
The C# coloum
Creating owner-drawn menus
Most
of the times menu items are strings, but sometimes pictures make
more sense than text strings. For example, a color menu should show
colors rather than text strings containing names of various colors.
It would make more sense for the user if colors like magenta and
cyan are shown as they are going to look, rather than as strings
saying Cyan and Magenta. If the colors were
shown, their meaning would be crystal clear.
Unfortunately, the MenuItem class does not provide a standard way to display
pictures/icons. For example, there is no Icon property you set to display an
icon automatically. However, the MenuItem class provides the capability for
non-standard drawing, often called owner-drawing.
Every menu item has a property called OwnerDraw. When the OwnerDraw property
is set to true, it indicates that the user, not Windows, will handle all drawing
of the menu item. .NET IDE gives full support for creating the owner-drawn menus.
In this article we will create a WinForm application with an owner-drawn menu.
The menu titled Color will display three menu items having icons
plus text. The icons will represent colors Red, Green
and Magenta. On clicking the menu items, the background of the form
gets filled with the selected color.
Create a WinForm application and add a Menu control to the form. Name the control
as m. Add the menu item Color to the menu m. Add three menu items
to the Color menu item. Name them as m1, m2 and m3 respectively.
Set the OwnerDraw property of these menu items to True.
When a menu is pulled down, the Framework first calls the MeasureItem event
handler for each owner-drawn menu item to determine how big the menu needs to
be. Then it calls the DrawItem event handler for each owner-drawn menu item
to actually do the drawing. Thats why we need to add event handlers for
both these events. We must add the event handlers for all the three menu items.
This will add total of six functions to the Form1 class. Lets now add
code to these handlers. Look at the MeasureItem event handler for the m1 menu
item.
private void m1_MeasureItem ( object sender, MeasureItemEventArgs
e )
{
e.ItemHeight = 20 ;
e.ItemWidth
= 80 ;
}
The MeasureItemEventArgs class provides data for the MeasureItem event. The
properties we need to set are ItemHeight and ItemWidth. We will need the height
of the menu item, which is the greater than the icon height or the font height
plus a few pixels, and the width of the menu. We will do the actual drawing
in the DrawItem event handler. The handler is given below.
private void m1_DrawItem ( object sender, DrawItemEventArgs
e )
{
e.Graphics.FillRectangle
( SystemBrushes.Control, e.Bounds ) ;
e.Graphics.DrawIcon
( new Icon ( C:\\icon1.ico ), e.Bounds.Left + 3, e.Bounds.Top +
3 ) ;
Brush br = new SolidBrush
( Color.Blue ) ;
e.Graphics.DrawString
( Red, new Font ( Courier New, 9 ), br,
( float )( e.Bounds.Left
+ 35 ), ( float )
( e.Bounds.Top + 2 )
) ;
}
The DrawItemEventArgs class contains all the information needed for the user
to paint the specified item, including the item index, the Rectangle and the
Graphics on which the drawing should be done. In this handler, firstly, we have
filled the bounds of the menu item with the standard control color. This is
necessary to display the bounding rectangle around the icon. Otherwise the icons
will get mixed up.
Next, we have drawn the icon on the menu item using the DrawIcon( ) method.
We have left the suitable number of pixels from left and top of the icon. Next
to the icon we have displayed the string mentioning the color name. While drawing
the string, we must leave the space where the icon has been drawn. We must also
keep suitable distance from the icon. Thats why we have left 35 pixels
from left side of the menu item bounds.
The MeasureItem and DrawItem event handlers for the other two menu items are
same. Only the icon files are different.
Add the Click event handlers for the menu items and set the BackColor property
of the form to respective color.
Creating one menu item having three owner drawn menu items is quite manageable,
although it results into repetition of code. We can avoid this by inheriting
a class from the MenuItem class and handling the event handlers in it.
Create our own iconmenuitem class derived from the MenuItem class. This class
is given below.
class iconmenuitem : MenuItem
{
Icon m_icon ;
string mtext ;
public iconmenuitem( )
{
}
public iconmenuitem
( string menutext,
EventHandler eh, Shortcut sh,
Icon ico ) : base ( menutext, eh, sh )
{
this.OwnerDraw
= true ;
this.DrawItem
+= new DrawItemEventHandler ( drawitem ) ;
this.MeasureItem
+= new MeasureItemEventHandler ( measureitem ) ;
m_icon =
ico ;
mtext
= menutext ;
}
private void drawitem
( object sender,DrawItemEventArgs e )
{
e.Graphics.FillRectangle
( SystemBrushes.Control, e.Bounds ) ;
e.Graphics.DrawIcon
( m_icon, e.Bounds.Left + 3, e.Bounds.Top + 3 ) ;
Brush br
= new SolidBrush ( Color.Blue ) ;
e.Graphics.DrawString
( mtext, new Font ( Courier New, 10 ), br,
( float )(
e.Bounds.Left + this.m_icon.Width + 5 ),
( float )
( e.Bounds.Top + 2 ) ) ;
}
private
void measureitem ( object sender, MeasureItemEventArgs e )
{
e.ItemHeight = 20 ;
e.ItemWidth = 80 ;
}
}
In this class we have provided the default constructor and a four-argument constructor.
To this constructor we have passed the menu text and the icon to be displayed.
We have set the OwnerDraw property to true and added the DrawItem and MeasureItem
event handlers. We have stored the icon and menu text passed to the constructor
to some data members of iconmenuitem class. The event handlers drawitem( ) and
measureitem( ) contains the same code we saw above.
We would have a Menu control named m. The menu m will have one menu item m1
titled Color and Color menu item will have menu items
m2 and m3. The m1 menu item is created by calling default constructor as shown
below.
m1 = new ownerdrawn.iconmenuitem( ) ;
Now create the menu items m2 and m3 using the iconmenuitem class as shown below.
Add this code to the constructor of the Form1 class after the call to the InitializeComponent(
) method.
Icon i1 = new Icon ( C:\\icon1.ico ) ;
m2 = new iconmenuitem ( Red,
new EventHandler ( m2_click ),
new Shortcut( ), i1 ) ;
Icon i2 = new Icon ( C:\\icon2.ico ) ;
m3 = new iconmenuitem ( Green,
new EventHandler ( m3_click ),
new Shortcut( ), i2 ) ;
m1.MenuItems.AddRange ( new
System.Windows.Forms.MenuItem[ ]
{ m2, m3 } ) ;
Add m1, m2 and m3 as data members of type iconmenuitem to the Form1 class.
The Click event handler for the m2 menu item is given below. In the same way
add the event handler for the m3 menu item.
private void m2_click ( object sender, System.EventArgs e
)
{
BackColor = Color.Red ;
}
The output of the program is shown below.

 |
Yashavant Kanetkar, one of
the first Express Computer columnists, is an established software
expert, speaker and author with several best-sellers to his
credit, including titles like “Let Us C” and the “Fundas” series.
Contact him at kanetkar@dcubesoft.com |
|