Microsoft KB Archive/888168

= How to create a custom menu in Visual Basic .NET or in Visual Basic 2005 =

Article ID: 888168

Article Last Modified on 5/11/2007

-

APPLIES TO


 * Microsoft Visual Basic 2005
 * Microsoft Visual Basic .NET 2003 Standard Edition
 * Microsoft Visual Basic .NET 2002 Standard Edition

-





SUMMARY
Learn how to create a custom menu in Microsoft Visual Basic .NET or Microsoft Visual Basic 2005 through both discussions and code examples.



IN THIS TASK

 * INTRODUCTION
 * Extend the MenuItem class
 * Declare a Font object and an Icon object for the MenuItem class
 * Add items to your menu
 * Draw your menu
 * Create a keyboard shortcut for the menu item
 * Highlight the menu item
 * Code example



INTRODUCTION
This article describes how to create a custom menu in Microsoft Visual Basic .NET or in Microsoft Visual Basic 2005. You create a custom menu by inheriting the MainMenu control and by adding properties to the items of the MainMenu control.

back to the top

Extend the MenuItem class
The MenuItem class does not provide a built-in way of displaying an icon. For example, there is no Icon property that you can set to display an icon. When a Microsoft .NET Framework class does not provide a feature that you want, you can extend that class, and you can provide the feature yourself.

You can extend the MenuItem class so that you can create an owner-drawn menu item. An owner-drawn menu item means that the developer is responsible for drawing the MenuItem class on the screen.

To extend the MenuItem class, use the following class inheritance syntax. Public Class MyIconMenu Inherits MenuItem End Class back to the top

Declare a Font object and an Icon object for the MenuItem class
When you inherit from the MenuItem class, you inherit its properties, methods, and events. You can create your own icon for your custom class by overriding the behavior of two of the methods that you inherit. You override the behavior of the OnMeasureItem method and of the OnDrawItem method. You must also declare private fields within your custom class to hold a Font object and an Icon object. You need a Font object so that your custom class can contain text in addition to icons.

If you require a way for developers who use your custom class to initialize your private fields, use the constructor of your custom class. A Visual Basic .NET 2003 constructor is a special method that is called New. The New method is called by the .NET Framework when your custom class is instantiated. By using Visual Basic .NET 2003, you can pass parameters to your constructor.

Visual Basic .NET 2003 also supports method overloading. You can define the same method many times, as long as the method signatures are unique.

By using constructors and method overloading, you can let developers initialize the private fields of your custom class. The code for your custom class may look similar to the following code example. Public Class MyIconMenu Inherits MenuItem Private font As Font Private icon As Icon

Sub New(ByVal menuText As String) MyClass.New(menuText, Nothing, Shortcut.None, Nothing) End Sub

Sub New(ByVal menuText As String, ByVal handler As EventHandler, ByVal shortcut As Shortcut, ByVal ico As icon) MyBase.New(menuText, handler, shortcut) Me.icon = ico Me.font = New Font(&quot;Arial&quot;, 8) Me.OwnerDraw = True End Sub End Class Notice that you have used method overloading on your constructor so that the developer has the option of having a menu item with an icon or a menu item without an icon. You must also set the OwnerDraw property of your custom class to the true value if you want to display an icon. This step is important because if this step is not completed, no icons are displayed on your menu.

back to the top

Add items to your menu
Examine the two methods that must be overridden. The OnMeasureItem method is called when your menu is drawn. The OnMeasureItem method lets you specify the size of your menu by setting two properties of the MeasureItemEventArgs constructor. The two properties of the MeasureItemEventArgs constructor that you set are the ItemHeight property and the ItemWidth property. These settings are passed as parameters to the OnMeasureItem method.

You may want to determine the height of the menu item based on the height of the icon. This may or may not always be appropriate. Typically, the height of the text of the menu item should not exceed the height of the icon.

To determine the width of your menu, you must know the width of the string that is displayed in the menu item. You can use the StringFormat object to retrieve this information. This object can be found in the System.Drawing namespace. When you measure the width of the menu item, you must also consider the icon.

The code for your OnMeasureItem method may be similar to the following code example. Protected Overrides Sub OnMeasureItem(ByVal e As MeasureItemEventArgs) MyBase.OnMeasureItem(e) Dim sf As StringFormat = New StringFormat

sf.HotkeyPrefix = HotkeyPrefix.Show sf.SetTabStops(50, New Single {0})

e.ItemHeight = Me.icon.Height + 6 e.ItemWidth = CInt(e.Graphics.MeasureString(AppendShortcut, _ Me.font, 1000, sf).Width) + Me.icon.Width + 5 sf.Dispose sf = Nothing End Sub back to the top

Draw your menu
After you specify the size of your menu, you must draw your menu by using the OnDrawItem method of your custom class. This method is passed to the DrawItemEventArgs object. You can use the DrawItemEventArgs object to obtain a Graphics object for your menu item. This lets you draw directly on the surface of your menu by using the powerful GDI+ features that are available in the .NET Framework. First, draw a background color. Then, draw the icon. Last, draw the text of the menu item.

The code for your menu may be similar to the following code example. Protected Overrides Sub OnDrawItem(ByVal e As DrawItemEventArgs) Dim br As Brush Dim sf As StringFormat

MyBase.OnDrawItem(e) e.Graphics.FillRectangle(SystemBrushes.Control, e.Bounds) If Not (Me.icon Is Nothing) Then e.Graphics.DrawIcon(Me.icon, e.Bounds.Left + 3, e.Bounds.Top + 3) End If

sf = New StringFormat sf.HotkeyPrefix = HotkeyPrefix.Show sf.SetTabStops(50, New Single {0}) br = New SolidBrush(SystemColors.WindowText) e.Graphics.DrawString(AppendShortcut, Me.font, br, e.Bounds.Left + _                         Me.icon.Width + 10, e.Bounds.Top + 2, sf) 'Clean up resources. br.Dispose br = Nothing sf.Dispose sf = Nothing End Sub back to the top

Create a keyboard shortcut for the menu item
In the code examples, the AppendShortcut function is called in both the OnMeasureItem method and the OnDrawItem method. You could measure and draw your string based on the Text property of the menu item. However, this does not consider the fact that the menu item might have a keyboard shortcut. If the menu item does have a keyboard shortcut, you must display the keyboard shortcut and increase the width of the menu item. You must represent the keyboard shortcut as a string. The AppendShortcut function represents the keyboard shortcut as a string and appends the shortcut string to the existing menu item text.

The code for the AppendShortcut function may be similar to the following code example. Private Function AppendShortcut As String Dim s As String s = Me.Text ' Check to see if we have a shortcut. ' If so, append it to our existing text. If Me.ShowShortcut And Me.Shortcut <> Shortcut.None Then Dim k As Keys = CType(Shortcut, Keys) s = s & Convert.ToChar(9) & _ TypeDescriptor.GetConverter(GetType(Keys)).ConvertToString(k) End If  Return s End Function back to the top

Highlight the menu item
After you create a basic icon menu item, you may want to highlight the menu item as it is selected. You must draw a border and highlight the text in the OnDrawItem method.

back to the top

Code example
The following code example is the complete code for your custom class. This code example includes the code to highlight the menu item. ' Form1.vb Public Class Form1 Inherits System.Windows.Forms.Form


 * 1) Region &quot; Windows Form Designer generated code &quot;

Public Sub New

MyBase.New

'This call is required by the Windows Form Designer.

InitializeComponent

'Add any initialization after the InitializeComponent call.

End Sub

'Form overrides dispose to clean up the component list.

Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

If disposing Then

If Not (components Is Nothing) Then

components.Dispose

End If

End If

MyBase.Dispose(disposing)

End Sub

'Required by the Windows Form Designer.

Private components As System.ComponentModel.IContainer

'Note The following procedure is required by the Windows Form Designer.

'It can be modified by using the Windows Form Designer.

'Do not modify it by using the code editor.

Friend WithEvents MainMenu1 As System.Windows.Forms.MainMenu

Friend WithEvents MenuItem1 As System.Windows.Forms.MenuItem

 Private Sub InitializeComponent

Me.MainMenu1 = New System.Windows.Forms.MainMenu

Me.MenuItem1 = New System.Windows.Forms.MenuItem

Me.MainMenu1.MenuItems.AddRange(New System.Windows.Forms.MenuItem {Me.MenuItem1})

Me.MenuItem1.Index = 0

Me.MenuItem1.Text = &quot;&quot;

Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)

Me.ClientSize = New System.Drawing.Size(292, 273)

Me.Menu = Me.MainMenu1

Me.Name = &quot;Form1&quot;

Me.Text = &quot;Form1&quot;

End Sub


 * 1) End Region

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

'Loading the MyIconMenu onto the first menu in MainMenu1.

Dim ico As Icon = New Icon(&quot;c:\GSA.ico&quot;)

Dim fm As MyIconMenu = New MyIconMenu(&quot;Testing&quot;, Nothing, Shortcut.None, ico)

MainMenu1.MenuItems(0).MenuItems.Add(fm)

End Sub

End Class

' MyIconMenu.vb

Imports System

Imports System.ComponentModel

Imports System.Drawing

Imports System.Drawing.Drawing2D

Imports System.Drawing.Text

Imports System.Windows.Forms

Public Class MyIconMenu

Inherits MenuItem

Private font As font

Private icon As icon

'Set properties for border highlighting.

Private borderWidth As Integer = 1

Private borderColor As Color = Color.DarkBlue

Sub New(ByVal menuText As String, ByVal handler As EventHandler, _

ByVal shortcut As Shortcut, ByVal ico As icon)

MyBase.New(menuText, handler, shortcut)

Me.icon = ico

Me.font = New Font(&quot;Arial&quot;, 8)

Me.OwnerDraw = True

End Sub

Public Overloads Sub Dispose

Me.font.Dispose

Me.font = Nothing

Me.icon.Dispose

Me.icon = Nothing

MyBase.Dispose

End Sub

Protected Overrides Sub OnMeasureItem(ByVal e As MeasureItemEventArgs)

MyBase.OnMeasureItem(e)

Dim sf As StringFormat = New StringFormat

sf.HotkeyPrefix = HotkeyPrefix.Show

sf.SetTabStops(50, New Single {0})

e.ItemHeight = Me.icon.Height + 6

e.ItemWidth = CInt(e.Graphics.MeasureString(AppendShortcut, _

Me.font, 1000, sf).Width) + Me.icon.Width + 5

sf.Dispose

sf = Nothing

End Sub

Protected Overrides Sub OnDrawItem(ByVal e As DrawItemEventArgs)

Dim br As Brush

Dim sf As StringFormat

MyBase.OnDrawItem(e)

If CBool(e.State And DrawItemState.Selected) Then

'Draw a border to highlight the menu.

e.Graphics.FillRectangle(SystemBrushes.HighlightText, _

e.Bounds)

ControlPaint.DrawBorder(e.Graphics, e.Bounds, _

Me.borderColor, Me.borderWidth, _

ButtonBorderStyle.Solid, _

Me.borderColor, Me.borderWidth, _

ButtonBorderStyle.Solid, _

Me.borderColor, Me.borderWidth, _

ButtonBorderStyle.Solid, _

Me.borderColor, Me.borderWidth, _

ButtonBorderStyle.Solid)

Else

e.Graphics.FillRectangle(SystemBrushes.Control, e.Bounds)

End If

If Not (Me.icon Is Nothing) Then

e.Graphics.DrawIcon(Me.icon, e.Bounds.Left + 3, _

e.Bounds.Top + 3)

End If

sf = New StringFormat

sf.HotkeyPrefix = HotkeyPrefix.Show

sf.SetTabStops(50, New Single {0})

br = New SolidBrush(SystemColors.WindowText)

e.Graphics.DrawString(AppendShortcut, Me.font, br, _

e.Bounds.Left + Me.icon.Width + 10, _

e.Bounds.Top + 2, sf)

'Clean up resources.

br.Dispose

br = Nothing

sf.Dispose

sf = Nothing

End Sub

Private Function AppendShortcut As String

Dim s As String

s = Me.Text

' Check to see if we have a shortcut.

' If so, append it to our existing text.

If Me.ShowShortcut And Me.Shortcut <> Shortcut.None Then

' Use TypeDescriptor to get a string representation of a

' Shortcut class.

Dim k As Keys = CType(Shortcut, Keys)

s = s & Convert.ToChar(9) & _

TypeDescriptor.GetConverter(GetType(Keys)).ConvertToString(k)

End If

Return s

End Function

End Class Note You must change the code in Visual Basic 2005. By default, Visual Basic creates two files for the project when you create a Windows Forms project. If the form is named Form1, the two files that represent the form are named Form1.vb and Form1.Designer.vb. You write the code in the Form1.vb file. The Windows Forms Designer writes the code in the Form1.Designer.vb file. The Windows Forms Designer uses the partial keyword to divide the implementation of Form1 into two separate files. This behavior prevents the designer-generated code from being interspersed with your code.

For more information about the new Visual Basic 2005 language enhancements, visit the following Microsoft Developer Network (MSDN) Web site:

http://msdn2.microsoft.com/en-us/library/ms379584(vs.80).aspx

For more information about partial classes and the Windows Forms Designer, visit the following MSDN Web site:

http://msdn2.microsoft.com/en-us/library/ms171843.aspx

back to the top

Keywords: kbvs2005swept kbvs2005applies kbhowtomaster kbprogramming kbmacroexample kbexpertiseinter kbhowto KB888168

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.