Click here to Skip to main content
Click here to Skip to main content

Customizable MainMenu on C#

, 23 Dec 2004
Rate this:
Please Sign up or sign in to vote.
An article on custom main menus and owner drawing.

Sample Image

Introduction

This article describes a way to customize the main menu of our application in C#. It can be completely and easily changed. This is my first article and I hope that it may be of some use.

Background

I've made this article from a code that I have found in this page, which I strongly recommend reading. Actually, the code is very similar, the main difference resides in the fact that I worked around a couple of limitations in the original code. The first limitation regards the fact that the code presented in the original article sets the size of the menu items which implies that they are not dynamic. The second limitation resides in the fact that when you draw your own menu, all the special characters like the separator "-" character (creates a line that divides two items) are not recognized. There is another limitation. You can't change the menus' color, only the items'!!! The rest of the menu (where you haven't created items) won't change its color. Try to create the menu according to the original article, but make the menu blue and you'll see what I'm saying.

Using the code

The idea is to create a regular main menu and then define the OwnerDraw variable so that we have to do the drawing and then define the DrawItem() and MeasureItem() functions to draw our menu. We will have to do this to every item in our menu. Luckily for us, we will only need to create two DrawItem() and MeasureItem() functions, to do the job. One takes care of the main menu items and the other does the dropdown menus when we hit a main menu item.

To take care of the color problem, we have to crate an extra main menu item which will be disabled, and then for its drawing, we will use a special function.

  1. Create your menu as always (using MainMenu in the toolbox, or whatever) and make an extra main menu item.

    Creation of the menu

  2. In the Items proprieties, define the OwnerDraw parameter to True, and in the "extra" item, set the Enable parameter to False.
  3. Add this code to your application:
    //Some colors I'll use.
    private Color grad1=Color.FromArgb(165,194,245);
    private Color grad2=Color.FromArgb(209,232,255);
    private Color grad3=Color.FromArgb(255,210,151);
    private Color grad4=Color.FromArgb(241,241,231);
    private Color linhalight=Color.FromArgb(169,184,215);
    private Color linha=Color.FromArgb(10,47,115);
    
    //
    //This is where we draw the main menu items.
    //
    private void OnDrawItem(object sender, 
                 System.Windows.Forms.DrawItemEventArgs e)
    {
        //rectangle that contains the dimentions of the item.
        Rectangle rc = new Rectangle(e.Bounds.X , 
                  e.Bounds.Y, e.Bounds.Width, e.Bounds.Height);
    
        //draws the button.
        e.Graphics.FillRectangle(new SolidBrush(grad1),rc);
    
        // Cast the sender to MenuItem so you can access text property.
        MenuItem customItem = (MenuItem) sender;
    
        // Create a Brush and a Font to draw the item's text.
        System.Drawing.Brush aBrush = System.Drawing.Brushes.Black;
        Font aFont = new Font("Microsoft Sans Serif", (float)8.25, 
                FontStyle.Regular, GraphicsUnit.Point);
        StringFormat sf = new StringFormat();
        sf.Alignment = StringAlignment.Center;
        rc.Y+=3;
        e.Graphics.DrawString(customItem.Text, aFont, aBrush, rc , sf );
        rc.Y-=3;
    
        //if the mouse is hover the item it changes the looks.
        if (e.State==(DrawItemState.NoAccelerator | DrawItemState.HotLight))
        {
            e.Graphics.FillRectangle(new LinearGradientBrush(rc,grad4, 
                             grad3,LinearGradientMode.Vertical) , rc);
            rc.Y+=3;
            e.Graphics.DrawString( customItem.Text , aFont , 
                       new SolidBrush(Color.Black), rc ,sf);
            rc.Y-=3;
            rc.Width--;
            e.Graphics.DrawRectangle(new Pen(Color.Blue,1), rc );
            rc.Width++;
        }
        else
        {
            //if the mouse hits the item it changes the looks.
            if ( e.State==(DrawItemState.NoAccelerator | DrawItemState.Selected))  
            {
                e.Graphics.FillRectangle(new LinearGradientBrush(rc, 
                           grad2,grad1,LinearGradientMode.Vertical) , rc);
                rc.Y+=3;
                e.Graphics.DrawString( customItem.Text , 
                           aFont , new SolidBrush(Color.Black), rc ,sf);
                rc.Y-=3;
                rc.Width--;
                e.Graphics.DrawRectangle(new Pen(new SolidBrush(linha)), rc );
                rc.Width++;
                e.Graphics.DrawLine(new Pen(linhalight,1),rc.X , 
                                    rc.Bottom, rc.Right, rc.Bottom);
            }
            else
                e.Graphics.DrawLine(new Pen(Color.White,1),rc.X , 
                                    rc.Bottom, rc.Right, rc.Bottom);
        }
        //draws the the focus rectangle.
        e.DrawFocusRectangle();
    }
    
    //
    //This is where we set the main menu items size.
    //
    private void OnMeasureItem(object sender, 
                 System.Windows.Forms.MeasureItemEventArgs e)
    {
        // Cast the sender to MenuItem so you can access text property.
        MenuItem customItem = (MenuItem) sender;
    
        // Create a Brush and a Font to draw the item's text.
        Font aFont = new Font("Microsoft Sans Serif", (float)8.25, 
                    FontStyle.Regular, GraphicsUnit.Point);
    
        //Gets the size of the drawn string.
        SizeF stringSize = e.Graphics.MeasureString(customItem.Text, aFont);
    
        //Sets the size of the menu item.
        e.ItemWidth=Convert.ToInt32(stringSize.Width);
        e.ItemHeight=20;
    }
    
    //
    //This is where we draw the dropdown menu items.
    //
    private void OnDrawItemSec(object sender, 
                 System.Windows.Forms.DrawItemEventArgs e)
    {
        //rectangle that contains the dimentions of the item.
        Rectangle rc = new Rectangle(e.Bounds.X , 
                       e.Bounds.Y, e.Bounds.Width, e.Bounds.Height);
    
        //draws the button.
        e.Graphics.FillRectangle(new SolidBrush(Color.White),rc);
    
        // Cast the sender to MenuItem so you can access text property.
        MenuItem customItem = (MenuItem) sender;
    
        // Create a Brush and a Font to draw the item's text.
        System.Drawing.Brush aBrush = System.Drawing.Brushes.Black;
        Font aFont = new Font("Microsoft Sans Serif", (float)8.25, 
                    FontStyle.Regular, GraphicsUnit.Point);
        StringFormat sf = new StringFormat();
        sf.Alignment = StringAlignment.Center;
    
        //if the text is the separator caracter ('-') draws the separator.
        if(customItem.Text=="-")
            e.Graphics.DrawLine(new Pen(Color.DarkGray,1), 
                        rc.X,rc.Y+2,rc.X+rc.Right,rc.Y+2);
        else
        {
            rc.Y+=3;
            e.Graphics.DrawString(customItem.Text, aFont, aBrush, rc , sf );
            rc.Y-=3;
        }
    
        //if the mouse is hover the item it changes the looks.
        if ( e.State==(DrawItemState.NoAccelerator | DrawItemState.Selected))  
        {
            e.Graphics.FillRectangle(new SolidBrush(grad1) , rc);
            rc.Y+=3;
            e.Graphics.DrawString( customItem.Text , aFont , 
                                   new SolidBrush(Color.Black), rc ,sf);
            rc.Y-=3;
            rc.Height--;
            rc.Width--;
            e.Graphics.DrawRectangle(new Pen(new SolidBrush(linha)), rc );
            rc.Height++;
            rc.Width++;
        }
        e.DrawFocusRectangle();
    }
    
    //
    //This is where we set the dropdown menu items.
    //
    private void OnMeasureItemSec(object sender, 
                 System.Windows.Forms.MeasureItemEventArgs e)
    {
        // Cast the sender to MenuItem so you can access text property.
        MenuItem customItem = (MenuItem) sender;
    
        // Create a Brush and a Font to draw the item's text.
        Font aFont = new Font("Microsoft Sans Serif", (float)8.25, 
        FontStyle.Regular, GraphicsUnit.Point);
    
        //Gets the size of the drawn string.
        SizeF stringSize = e.Graphics.MeasureString(customItem.Text, aFont);
        e.ItemWidth=Convert.ToInt32(stringSize.Width);
    
        //Sets the size of the menu item.(regards the separator case)
        if(customItem.Text=="-")
            e.ItemHeight=5;
        else
            e.ItemHeight=20;
    }
    
    //
    //This is where we draw the extra item to color the remaining menu.
    //
    private void OnDrawExtra(object sender, 
                 System.Windows.Forms.DrawItemEventArgs e)
    {
        Rectangle area = new Rectangle(e.Bounds.X , e.Bounds.Y, 
                         this.ClientRectangle.Right-
                         (e.Bounds.X-this.ClientRectangle.X-4), 19);
        e.Graphics.FillRectangle(new SolidBrush(grad1),area);
    }
  4. Now for the main menu items, define their events parameters and set the DrawItem as OnDrawItem (you've added above) and MeasureItem as OnMeasureItem. Do the same for the drop down items but this time using the OnDrawItemSec and the OnMeasureItemSec. For the extra item, we set the DrawItem event to do the OnDrawExtra.

Compile and see your menu's new look.

Limitations

This code is an improvement from the code on the original article, but it is still far from perfection. For example, the '&' special character problem. Like the '-' problem, the '&' instead of underlining the key character of our menu item, is drawn.

Example:

Item -> &View

Shows: &View

Instead of: View.

Another problem is that 'horrible' white line under the menu.

Hope you've liked the control.

History

23-12-2004

  • Version 1.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

João Martins
Software Developer
Portugal Portugal
I'm that guy that falls for the impossible...

Comments and Discussions

 
QuestionHow to draw menuitem's Shortcut? Pinmembercq_wxy8-Feb-06 19:08 
Generali need to change the menu hiegt Pinmembershabonaa29-Oct-05 7:38 
GeneralGone - the 'horrible' white line PinmemberMark Johnson29-Jul-05 1:29 
GeneralRe: Gone - the 'horrible' white line Pinmemberltinka18-Oct-05 2:00 
GeneralRe: Gone - the 'horrible' white line Pinmemberpsorr22-Nov-05 12:48 
Generalwhole menu not colored on maximized Pinmemberarfeena7-Jul-05 11:40 
GeneralRe: whole menu not colored on maximized PinmemberJoão Martins7-Jul-05 13:51 
GeneralRe: whole menu not colored on maximized Pinmembersergio.cruz.r10-Feb-06 2:51 
QuestionO.K. code. font hardcode ?? Pinmembermlavenne1-Apr-05 6:28 
You are providing good information to the newbies, however, you should mention that hardcoding the Font is not a good idea.
 
Especially within the OnMeasureItem, because you can't get in from the method itself. The DrawItemEventArgs has a Font property, but the MeasureItemEventArgs doesn't.
 
Without the font, it's pretty hard to measure an item.

GeneralThe white line problem Pinmemberjonnospam27-Feb-05 0:14 
GeneralRe: The white line problem PinmemberRadu Cosoveanu24-Aug-05 7:35 
QuestionHow to convert to VB.net PinmemberDavid M J29-Dec-04 12:29 
AnswerRe: How to convert to VB.net PinmemberBrazilianDudi29-Dec-04 14:00 
GeneralRe: How to convert to VB.net PinmemberDavid M J29-Dec-04 20:41 
GeneralRe: How to convert to VB.net PinmemberBrazilianDudi30-Dec-04 2:19 
GeneralRe: How to convert to VB.net PinmemberDavid M J30-Dec-04 12:14 
GeneralRe: How to convert to VB.net PinmemberJoão Martins30-Dec-04 14:32 
GeneralRe: How to convert to VB.net Pinmemberchelonian22-Feb-05 2:36 
GeneralRe: How to convert to VB.net PinmemberLordRhys4-Jan-05 4:40 
QuestionHow can I? Pinmemberguybou@gmail.com24-Dec-04 20:56 
AnswerRe: How can I? PinmemberJoão Martins25-Dec-04 3:34 
GeneralRe: How can I? Pinmemberguybou@gmail.com25-Dec-04 10:36 
GeneralTo draw the hot key underlined PinmemberEric Woodruff24-Dec-04 9:50 
GeneralRe: To draw the hot key underlined PinmemberJoão Martins25-Dec-04 3:35 
GeneralRe: To draw the hot key underlined PinmemberYurich12-Jan-05 11:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 24 Dec 2004
Article Copyright 2004 by João Martins
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid