Customizable MainMenu on C#






3.08/5 (9 votes)
Dec 24, 2004
3 min read

130008

848
An article on custom main menus and owner drawing.
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.
- Create your menu as always (using
MainMenu
in the toolbox, or whatever) and make an extra main menu item. - In the Items proprieties, define the
OwnerDraw
parameter to True, and in the "extra" item, set theEnable
parameter to False. - 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); }
- Now for the main menu items, define their events parameters and set the
DrawItem
asOnDrawItem
(you've added above) andMeasureItem
asOnMeasureItem
. Do the same for the drop down items but this time using theOnDrawItemSec
and theOnMeasureItemSec
. For the extra item, we set theDrawItem
event to do theOnDrawExtra
.
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.