Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Customizable MainMenu on C#

0.00/5 (No votes)
23 Dec 2004 3  
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