You are on page 1of 25

C Sharp RichMenuItem Una clase para crear

menús con iconos en Visual Basic y C# 2002 y


2003
Publicado el 26/Dic/2005
Actualizado el 26/Dic/2005
Autor: Guillermo 'guille' Som

Aquí te muestro el código de la clase RichMenuItem, con esa clase podrás crear elementos
de menús que utilicen imágens, y de una forma bastante fácil, por supuesto esta clase solo
es necesaria para las versiones 2002 y 2003 de Visual Basic y de C#, ya que la versión
2005 incluye menús en los que se pueden indicar las imágenes a usar.

Del código mostrado, la clase de C# es la original incluida en SharpDevelop, pero la de


Visual Basic está modificada para aceptar otras propiedades y formas de mostrarlo, (lee los
comentarios para saber cuales son esas diferencias).

Al final de esta página tienes la autorización del autor de la clase de C# para que la
publique sin estar atado a la licencia GPL que se aplica al proyecto SharpDevelop y a cada
uno de sus componentes.

En esta otra página tienes un ejemplo para Visual Basic 2003 de cómo usar esa clase.
En ese mismo ejemplo puedes encontrar una clase para extraer iconos desde una imagen
con varios iconos, esas imágenes serán las que se usen en los menús.
En esa página con el ejemplo, también hay una clase para seleccionar el dibujo a mostrar a
partir de una imagen con varios iconos (también se incluye esa imagen en esa página), de
forma que sea fácil indicar el icono que quieres usar.

Espero que lo disfrutes.

Nos vemos.
Guillermo

El código para VB .NET


Este es el código de la clase RichMenuItem con algunas modificaciones sobre el
original de C#.
'------------------------------------------------------------------------
------
' RichMenuItem.vb
(15/Ene/02)
' Basado en RichMenuItem.cs de Mike Krueger autor de SharpDevelop
'
' Revisado 17/Jun/2004 Nuevo estilo de menús (Office2003)
' La banda de los menús la hago más ancha (sólo
Office2003)
' Al crear la instancia se puede indicar el icono
' Revisado 19/Jun/2004 Propiedad compartida para el estilo de los menús
' Revisado 20/Jun/2004 Añado propiedad Description para mostrar la info
del menú
'
' ©Guillermo 'guille' Som, 2002-2004
'------------------------------------------------------------------------
------
' Este código, al igual que el original, es libre y se puede redistribuir
' y/o modificar bajo los términos de la GNU General Public License
publicada
' por Free Software Foundation versión 2 o posterior (si así lo estimas
oportuno)
'------------------------------------------------------------------------
------
'// RichMenuItem.cs
'// Copyright (c) 2001 Mike Krueger
'//
'// This program is free software; you can redistribute it and/or modify
'// it under the terms of the GNU General Public License as published by
'// the Free Software Foundation; either version 2 of the License, or
'// (at your option) any later version.
'//
'// This program is distributed in the hope that it will be useful,
'// but WITHOUT ANY WARRANTY; without even the implied warranty of
'// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
'// GNU General Public License for more details.
'//
'// You should have received a copy of the GNU General Public License
'// along with this program; if not, write to the Free Software
'// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
'------------------------------------------------------------------------
------
Option Strict On

Imports Microsoft.VisualBasic
Imports System
Imports System.Drawing
Imports System.Diagnostics
Imports System.Drawing.Text
Imports System.Drawing.Imaging
Imports System.Windows.Forms

'Namespace elGuille.Components

Public Class RichMenuItem : Inherits MenuItem


Private Shared mnuStyle As IconMenuStyle = IconMenuStyle.VSNet
Public Shared Property DefaultMenuStyle() As IconMenuStyle
Get
Return mnuStyle
End Get
Set(ByVal value As IconMenuStyle)
mnuStyle = value
End Set
End Property
'
Private _shortcuttext As String = ""
Private _stringformat As StringFormat = New StringFormat
Private _icon As Bitmap = Nothing
Private _style As MenuItemStyleDrawer = Nothing
Private _menustyle As IconMenuStyle = IconMenuStyle.VSNet
'
Private shortcuttextwidth As Integer
'
' Descripción para usar en las barras de estado, etc.
(20/Jun/04)
Private _description As String
Public Property Description() As String
Get
Return _description
End Get
Set(ByVal value As String)
_description = value
End Set
End Property
'
Public Shadows Function CloneMenu() As RichMenuItem
Dim rmnu As New RichMenuItem(Me.Icon, Me.Text)
rmnu.Checked = Me.Checked
Return rmnu
End Function
Public Shadows Function CloneMenu(ByVal handler As EventHandler) As
RichMenuItem
Dim rmnu As New RichMenuItem(Me.Icon, Me.Text, handler,
Me.Description)
rmnu.Checked = Me.Checked
Return rmnu
End Function
Public Shadows Function CloneMenu(ByVal handler As EventHandler,
ByVal description As String) As RichMenuItem
Dim rmnu As New RichMenuItem(Me.Icon, Me.Text, handler,
description)
rmnu.Checked = Me.Checked
Return rmnu
End Function
'
Public Property MenuStyle() As IconMenuStyle
Get
Return _menustyle
End Get
Set(ByVal value As IconMenuStyle)
' asignar la variable compartida,
(19/Jun/04)
' para que los nuevos menús usen el último estilo
mnuStyle = value
Select Case value
Case IconMenuStyle.Office2000
_style = New Office2000Style
OwnerDraw = True

Case IconMenuStyle.Office2003
_style = New Office2003Style
OwnerDraw = True

Case IconMenuStyle.VSNet
_style = New VSNetStyle
OwnerDraw = True

Case Else
_style = Nothing
OwnerDraw = False

End Select
End Set
End Property
'
Public Overloads Property ShortCutText() As String
Get
Return _shortcuttext
End Get
Set(ByVal Value As String)
_shortcuttext = Value
End Set
End Property
'
Public Property Icon() As Bitmap
Get
Return _icon
End Get
Set(ByVal Value As Bitmap)
_icon = Value
End Set
End Property
'
Public Sub New()
MyBase.New()
MenuStyle = mnuStyle
End Sub
'
' Sin estilo ni icono
Public Sub New(ByVal text As String)
MyBase.New(text)
MenuStyle = mnuStyle
End Sub
Public Sub New(ByVal text As String, ByVal items As RichMenuItem())
MyBase.New(text, items)
MenuStyle = mnuStyle
End Sub
Public Sub New(ByVal text As String, ByVal handler As EventHandler)
MyBase.New(text, handler)
MenuStyle = mnuStyle
End Sub
Public Sub New(ByVal text As String, ByVal handler As EventHandler,
ByVal shortcut As Shortcut)
Me.New(text, handler)
Me.Shortcut = shortcut
MenuStyle = mnuStyle
End Sub
'
' Usando el estilo en el primer parámetro
Public Sub New(ByVal style As IconMenuStyle)
MyBase.New()
MenuStyle = style
End Sub
Public Sub New(ByVal style As IconMenuStyle, ByVal text As String)
MyBase.New(text)
MenuStyle = style
End Sub
Public Sub New(ByVal style As IconMenuStyle, ByVal text As String,
ByVal items As RichMenuItem())
MyBase.New(text, items)
MenuStyle = style
End Sub
Public Sub New(ByVal style As IconMenuStyle, ByVal text As String,
ByVal handler As EventHandler)
MyBase.New(text, handler)
MenuStyle = style
End Sub
Public Sub New(ByVal style As IconMenuStyle, ByVal text As String,
ByVal handler As EventHandler, ByVal shortcut As Shortcut)
Me.New(style, text, handler)
Me.Shortcut = shortcut
End Sub
'
' con iconos y estilo
(17/Jun/04)
Public Sub New(ByVal icono As Bitmap, ByVal style As IconMenuStyle,
ByVal text As String)
MyBase.New(text)
MenuStyle = style
Me.Icon = icono
End Sub
Public Sub New(ByVal icono As Bitmap, ByVal style As IconMenuStyle,
ByVal text As String, ByVal items As RichMenuItem())
MyBase.New(text, items)
MenuStyle = style
Me.Icon = icono
End Sub
Public Sub New(ByVal icono As Bitmap, ByVal style As IconMenuStyle,
ByVal text As String, ByVal handler As EventHandler)
MyBase.New(text, handler)
MenuStyle = style
Me.Icon = icono
End Sub
Public Sub New(ByVal icono As Bitmap, ByVal style As IconMenuStyle,
ByVal text As String, ByVal handler As EventHandler, ByVal shortcut As
Shortcut)
Me.New(icono, style, text, handler)
Me.Shortcut = shortcut
End Sub
'
' con iconos sin estilo de menú
(19/Jun/04)
Public Sub New(ByVal icono As Bitmap, ByVal text As String)
MyBase.New(text)
Me.Icon = icono
MenuStyle = mnuStyle
End Sub
Public Sub New(ByVal icono As Bitmap, ByVal text As String, ByVal
items As RichMenuItem())
MyBase.New(text, items)
Me.Icon = icono
MenuStyle = mnuStyle
End Sub
Public Sub New(ByVal icono As Bitmap, ByVal text As String, ByVal
handler As EventHandler)
MyBase.New(text, handler)
Me.Icon = icono
MenuStyle = mnuStyle
End Sub
Public Sub New(ByVal icono As Bitmap, ByVal text As String, ByVal
handler As EventHandler, ByVal shortcut As Shortcut)
Me.New(icono, text, handler)
Me.Shortcut = shortcut
MenuStyle = mnuStyle
End Sub
'
' constructores con la descripción
Public Sub New(ByVal text As String, ByVal description As String)
MyBase.New(text)
MenuStyle = mnuStyle
_description = description
End Sub
Public Sub New(ByVal text As String, ByVal items As RichMenuItem(),
ByVal description As String)
MyBase.New(text, items)
MenuStyle = mnuStyle
_description = description
End Sub
Public Sub New(ByVal text As String, ByVal handler As EventHandler,
ByVal description As String)
MyBase.New(text, handler)
MenuStyle = mnuStyle
_description = description
End Sub
Public Sub New(ByVal text As String, ByVal handler As EventHandler,
ByVal shortcut As Shortcut, ByVal description As String)
Me.New(text, handler, description)
Me.Shortcut = shortcut
MenuStyle = mnuStyle
End Sub
'
' Usando el estilo en el primer parámetro
'Public Sub New(ByVal style As IconMenuStyle, ByVal description As
String)
' MyBase.New()
' MenuStyle = style
' _description = description
'End Sub
Public Sub New(ByVal style As IconMenuStyle, ByVal text As String,
ByVal description As String)
MyBase.New(text)
MenuStyle = style
_description = description
End Sub
Public Sub New(ByVal style As IconMenuStyle, ByVal text As String,
ByVal items As RichMenuItem(), ByVal description As String)
MyBase.New(text, items)
MenuStyle = style
_description = description
End Sub
Public Sub New(ByVal style As IconMenuStyle, ByVal text As String,
ByVal handler As EventHandler, ByVal description As String)
MyBase.New(text, handler)
MenuStyle = style
_description = description
End Sub
Public Sub New(ByVal style As IconMenuStyle, ByVal text As String,
ByVal handler As EventHandler, ByVal shortcut As Shortcut, ByVal
description As String)
Me.New(style, text, handler, description)
Me.Shortcut = shortcut
End Sub
'
' con iconos y estilo
(17/Jun/04)
Public Sub New(ByVal icono As Bitmap, ByVal style As IconMenuStyle,
ByVal text As String, ByVal description As String)
MyBase.New(text)
MenuStyle = style
Me.Icon = icono
_description = description
End Sub
Public Sub New(ByVal icono As Bitmap, ByVal style As IconMenuStyle,
ByVal text As String, ByVal items As RichMenuItem(), ByVal description As
String)
MyBase.New(text, items)
MenuStyle = style
Me.Icon = icono
_description = description
End Sub
Public Sub New(ByVal icono As Bitmap, ByVal style As IconMenuStyle,
ByVal text As String, ByVal handler As EventHandler, ByVal description As
String)
MyBase.New(text, handler)
MenuStyle = style
Me.Icon = icono
_description = description
End Sub
Public Sub New(ByVal icono As Bitmap, ByVal style As IconMenuStyle,
ByVal text As String, ByVal handler As EventHandler, ByVal shortcut As
Shortcut, ByVal description As String)
Me.New(icono, style, text, handler, description)
Me.Shortcut = shortcut
End Sub
'
' con iconos sin estilo de menú
(19/Jun/04)
Public Sub New(ByVal icono As Bitmap, ByVal text As String, ByVal
description As String)
MyBase.New(text)
Me.Icon = icono
MenuStyle = mnuStyle
_description = description
End Sub
Public Sub New(ByVal icono As Bitmap, ByVal text As String, ByVal
items As RichMenuItem(), ByVal description As String)
MyBase.New(text, items)
Me.Icon = icono
MenuStyle = mnuStyle
description = description
End Sub
Public Sub New(ByVal icono As Bitmap, ByVal text As String, ByVal
handler As EventHandler, ByVal description As String)
MyBase.New(text, handler)
Me.Icon = icono
MenuStyle = mnuStyle
_description = description
End Sub
Public Sub New(ByVal icono As Bitmap, ByVal text As String, ByVal
handler As EventHandler, ByVal shortcut As Shortcut, ByVal description As
String)
Me.New(icono, text, handler, description)
Me.Shortcut = shortcut
MenuStyle = mnuStyle
End Sub
'
'
Protected Overrides Sub OnMeasureItem(ByVal e As
MeasureItemEventArgs)
MyBase.OnMeasureItem(e)

'// make shortcut text


If (Shortcut <> Shortcut.None) Then
Dim text As String = ""
Dim key As Integer = Shortcut
Dim ch As Integer = key And &HFF
If ((Keys.Control And key) > 0) Then _
text &= "Ctrl+"
If ((Keys.Shift And key) > 0) Then _
text &= "Shift+"
If ((Keys.Alt And key) > 0) Then _
text &= "Alt+"

If (ch >= Shortcut.F1 And ch <= Shortcut.F12) Then


text &= "F" & (ch - Shortcut.F1 + 1)
ElseIf ((Keys.Insert And key) = Keys.Insert) Then
text &= "Ins"
Else
' mostrar la letra del acceso
(17/Jun/04)
text &= ChrW(ch)
End If
_shortcuttext = text
End If
If (MenuStyle <> IconMenuStyle.Standard) Then
If (text = "-") Then
e.ItemHeight = 8
e.ItemWidth = 4
Exit Sub 'Return
End If
Dim textwidth As Integer =
CType(e.Graphics.MeasureString(text, SystemInformation.MenuFont).Width,
Integer)
shortcuttextwidth =
CType(e.Graphics.MeasureString(ShortCutText,
SystemInformation.MenuFont).Width, Integer)
textwidth += shortcuttextwidth

e.ItemHeight = SystemInformation.MenuHeight
If (Parent Is Parent.GetMainMenu()) Then
e.ItemWidth = textwidth - 5 '// 5 is a magic number :)
Else
e.ItemWidth = Math.Max(160, textwidth + 15)
End If
End If
End Sub
'
Protected Overrides Sub OnSelect(ByVal e As EventArgs)
MyBase.OnSelect(e)
End Sub
'
Protected Overrides Sub OnDrawItem(ByVal e As DrawItemEventArgs)
MyBase.OnDrawItem(e)
Dim g As Graphics = e.Graphics
Dim bounds As Rectangle = e.Bounds
Dim selected As Boolean = (e.State And DrawItemState.Selected) >
0
Dim toplevel As Boolean = (Parent Is Parent.GetMainMenu())
Dim hasicon As Boolean = Not (Icon Is Nothing)

_style.DrawBackground(g, bounds, e.State, toplevel, hasicon)


If (hasicon) Then
_style.DrawIcon(g, Icon, bounds, selected, Enabled, Checked)
ElseIf (Checked) Then
_style.DrawCheckmark(g, bounds, selected)
End If

If (Text = "-") Then


_style.DrawSeparator(g, bounds)
Else
_style.DrawMenuText(g, bounds, Text, ShortCutText, Enabled,
toplevel, e.State)
End If
End Sub
End Class
'
'---
'
Public Enum IconMenuStyle
Standard
Office2000
Office2003
VSNet
End Enum

Public Interface MenuItemStyleDrawer


Sub DrawCheckmark(ByVal g As Graphics, ByVal bounds As Rectangle,
ByVal selected As Boolean)
Sub DrawIcon(ByVal g As Graphics, ByVal icon As Image, ByVal bounds
As Rectangle, ByVal selected As Boolean, ByVal enabled As Boolean, ByVal
ischecked As Boolean)
Sub DrawSeparator(ByVal g As Graphics, ByVal bounds As Rectangle)
Sub DrawBackground(ByVal g As Graphics, ByVal bounds As Rectangle,
ByVal state As DrawItemState, ByVal toplevel As Boolean, ByVal hasicon As
Boolean)
Sub DrawMenuText(ByVal g As Graphics, ByVal bounds As Rectangle,
ByVal text As String, ByVal shortcut As String, ByVal enabled As Boolean,
ByVal toplevel As Boolean, ByVal state As DrawItemState)
End Interface

' Nueva clase al estilo de Office2003


(17/Jun/04)
' Sólo los colores, sin efectos de degradados...
Public Class Office2003Style : Implements MenuItemStyleDrawer
Shared bgcolor As Color = Color.WhiteSmoke ' El
color de fondo de los menús
Dim ibgcolor As Color = Color.FromArgb(200, 215, 240) ' El
color de la banda izquierda de los menús
Shared sbcolor As Color = Color.FromArgb(255, 236, 196) ' color
de fondo del elemento seleccionado
Dim sbbcolor As Color = Color.FromArgb(60, 96, 192) ' Color
alrededor de la selección
'
Dim TEXTSTART As Integer = 24 '20
'
Public Shared ReadOnly Property BackColor() As Color
Get
Return bgcolor
End Get
End Property
Public Shared ReadOnly Property SelectedBackColor() As Color
Get
Return sbcolor
End Get
End Property
'
Public Sub DrawCheckmark(ByVal g As Graphics, ByVal bounds As
Rectangle, ByVal selected As Boolean) Implements
MenuItemStyleDrawer.DrawCheckmark
'ControlPaint.DrawMenuGlyph(g, New Rectangle(bounds.X + 2,
bounds.Y + 2, 14, 14), MenuGlyph.Checkmark)
'g.DrawRectangle(New Pen(sbbcolor), bounds.X + 1, bounds.Y + 1,
14 + 1, 14 + 1)
'
If selected = False Then
g.FillRectangle(New Pen(Color.Gold).Brush, bounds.X + 2,
bounds.Y + 2, 14 + 2, 14 + 1)
End If
g.DrawString("v", New Font(SystemInformation.MenuFont,
FontStyle.Bold), New Pen(SystemColors.MenuText).Brush, bounds.X + 2,
bounds.Y + 2)
'
End Sub

Public Sub DrawIcon(ByVal g As Graphics, ByVal icon As Image, ByVal


bounds As Rectangle, ByVal selected As Boolean, ByVal enabled As Boolean,
ByVal ischecked As Boolean) Implements MenuItemStyleDrawer.DrawIcon
If enabled Then
If selected Then
ControlPaint.DrawImageDisabled(g, icon, bounds.Left + 2,
bounds.Top + 2, Color.Black)
g.DrawImage(icon, bounds.Left + 1, bounds.Top + 1)
Else
g.DrawImage(icon, bounds.Left + 2, bounds.Top + 2)
End If
Else
ControlPaint.DrawImageDisabled(g, icon, bounds.Left + 2,
bounds.Top + 2, SystemColors.HighlightText)
End If
End Sub

Public Sub DrawSeparator(ByVal g As Graphics, ByVal bounds As


Rectangle) Implements MenuItemStyleDrawer.DrawSeparator
Dim y As Integer = CType(bounds.Y + bounds.Height / 2, Integer)
g.DrawLine(New Pen(SystemColors.ControlDark), bounds.X +
SystemInformation.SmallIconSize.Width + 7, y, bounds.X + bounds.Width -
2, y)
End Sub

Public Sub DrawBackground(ByVal g As Graphics, ByVal bounds As


Rectangle, ByVal state As DrawItemState, ByVal toplevel As Boolean, ByVal
hasicon As Boolean) Implements MenuItemStyleDrawer.DrawBackground
Dim selected As Boolean = (state And DrawItemState.Selected) > 0

If (selected OrElse ((state And DrawItemState.HotLight) > 0))


Then
If (toplevel AndAlso selected) Then '// draw toplevel,
selected menuitem
g.FillRectangle(New SolidBrush(ibgcolor), bounds)
ControlPaint.DrawBorder3D(g, bounds.Left, bounds.Top,
bounds.Width, bounds.Height, Border3DStyle.Flat, Border3DSide.Top Or
Border3DSide.Left Or Border3DSide.Right)
Else '// draw menuitem, selected OR toplevel, hotlighted
g.FillRectangle(New SolidBrush(sbcolor), bounds)
g.DrawRectangle(New Pen(sbbcolor), bounds.X, bounds.Y,
bounds.Width - 1, bounds.Height - 1)
End If
Else
If (Not toplevel) Then '// draw menuitem, unselected
g.FillRectangle(New SolidBrush(ibgcolor), bounds)
bounds.X += 16 + 5
bounds.Width -= 16 + 5
g.FillRectangle(New SolidBrush(bgcolor), bounds)
Else
'// draw toplevel, unselected menuitem
g.FillRectangle(SystemBrushes.Control, bounds)
End If
End If
End Sub

Public Sub DrawMenuText(ByVal g As Graphics, ByVal bounds As


Rectangle, ByVal text As String, ByVal shortcut As String, ByVal enabled
As Boolean, ByVal toplevel As Boolean, ByVal state As DrawItemState)
Implements MenuItemStyleDrawer.DrawMenuText
Dim stringformat As StringFormat = New StringFormat
stringformat.HotkeyPrefix = CType(IIf(((state And
DrawItemState.NoAccelerator) > 0), HotkeyPrefix.Hide, HotkeyPrefix.Show),
HotkeyPrefix)
Dim textwidth As Integer = CType(g.MeasureString(text,
SystemInformation.MenuFont).Width, Integer)
Dim shortcutwidth As Integer = CType(g.MeasureString(shortcut,
SystemInformation.MenuFont).Width, Integer)

Dim x As Integer = CType(IIf(toplevel, bounds.Left +


(bounds.Width - textwidth) / 2, bounds.Left + TEXTSTART), Integer)
Dim y As Integer = bounds.Top + 2
Dim brush As Brush = Nothing
If enabled Then
brush = New SolidBrush(SystemColors.MenuText)
Else
brush = New SolidBrush(Color.FromArgb(120,
SystemColors.MenuText))
End If
g.DrawString(text, SystemInformation.MenuFont, brush, x, y,
stringformat)
g.DrawString(shortcut, SystemInformation.MenuFont, brush,
bounds.Right - shortcutwidth - 10, bounds.Top + 2, stringformat)
End Sub
End Class

Public Class Office2000Style : Implements MenuItemStyleDrawer


Dim TEXTSTART As Integer = 20
'
Public Shared ReadOnly Property BackColor() As Color
Get
Return SystemColors.Menu
End Get
End Property
Public Shared ReadOnly Property SelectedBackColor() As Color
Get
Return SystemColors.Highlight
End Get
End Property
'
Public Sub DrawCheckmark(ByVal g As Graphics, ByVal bounds As
Rectangle, ByVal selected As Boolean) Implements
MenuItemStyleDrawer.DrawCheckmark
ControlPaint.DrawMenuGlyph(g, New Rectangle(bounds.X + 2,
bounds.Y + 2, 14, 14), MenuGlyph.Checkmark)
End Sub

Public Sub DrawIcon(ByVal g As Graphics, ByVal icon As Image, ByVal


bounds As Rectangle, ByVal selected As Boolean, ByVal enabled As Boolean,
ByVal ischecked As Boolean) Implements MenuItemStyleDrawer.DrawIcon
If (enabled) Then
g.DrawImage(icon, bounds.Left + 2, bounds.Top + 2)
Else
ControlPaint.DrawImageDisabled(g, icon, bounds.Left + 2,
bounds.Top + 2, SystemColors.Control)
End If
If (selected) Then _
ControlPaint.DrawBorder3D(g, bounds.Left, bounds.Top,
icon.Width + 3, icon.Height + 3, Border3DStyle.RaisedInner)
End Sub

Public Sub DrawSeparator(ByVal g As Graphics, ByVal bounds As


Rectangle) Implements MenuItemStyleDrawer.DrawSeparator
ControlPaint.DrawBorder3D(g, bounds.X, bounds.Y + 2,
bounds.Width, 3, Border3DStyle.Etched, Border3DSide.Top)
End Sub

Public Sub DrawBackground(ByVal g As Graphics, ByVal bounds As


Rectangle, ByVal state As DrawItemState, ByVal toplevel As Boolean, ByVal
hasicon As Boolean) Implements MenuItemStyleDrawer.DrawBackground
Dim selected As Boolean = (state And DrawItemState.Selected) > 0
If (selected OrElse ((state And DrawItemState.HotLight) > 0))
Then
If (toplevel) Then
'//
g.FillRectangle(SystemBrushes.Highlight, bounds);
ControlPaint.DrawBorder3D(g, bounds.Left, bounds.Top,
bounds.Width, bounds.Height, CType(IIf(selected,
Border3DStyle.SunkenOuter, Border3DStyle.RaisedInner), Border3DStyle),
Border3DSide.All)
Else
If (hasicon) Then
g.FillRectangle(SystemBrushes.Menu, New
Rectangle(bounds.X, bounds.Y, bounds.X +
SystemInformation.SmallIconSize.Width + 5, bounds.Height))
bounds.X += SystemInformation.SmallIconSize.Width + 5
bounds.Width -= SystemInformation.SmallIconSize.Width
+ 5
End If
g.FillRectangle(SystemBrushes.Highlight, bounds)
End If
Else
If (toplevel) Then
g.FillRectangle(SystemBrushes.Control, bounds)
Else
g.FillRectangle(SystemBrushes.Menu, bounds)
End If
End If
End Sub

Public Sub DrawMenuText(ByVal g As Graphics, ByVal Bounds As


Rectangle, ByVal Text As String, ByVal ShortCut As String, ByVal Enabled
As Boolean, ByVal TopLevel As Boolean, ByVal State As DrawItemState)
Implements MenuItemStyleDrawer.DrawMenuText
Dim selected As Boolean = (State And DrawItemState.Selected) > 0
Dim _stringformat As StringFormat = New StringFormat
_stringformat.HotkeyPrefix = CType(IIf(((State And
DrawItemState.NoAccelerator) > 0), HotkeyPrefix.Hide, HotkeyPrefix.Show),
HotkeyPrefix)
Dim shortcutwidth As Integer = CType(g.MeasureString(ShortCut,
SystemInformation.MenuFont).Width, Integer)
Dim textwidth As Integer = CType(g.MeasureString(Text,
SystemInformation.MenuFont).Width, Integer)
Dim x As Integer = CType(IIf(TopLevel, Bounds.Left +
(Bounds.Width - textwidth) / 2, Bounds.Left + TEXTSTART), Integer)

Dim y As Integer = Bounds.Top + 2


If (Enabled) Then
'// normal draw
Dim color As Color = CType(IIf((selected And (Not TopLevel)),
color.White, SystemColors.MenuText), Color)
g.DrawString(Text, SystemInformation.MenuFont, New
SolidBrush(color), x, y, _stringformat)
g.DrawString(ShortCut, SystemInformation.MenuFont, New
SolidBrush(color), Bounds.Left + 130, Bounds.Top + 2, _stringformat)
Else
'// disabled menuitem draw
If (Not selected) Then
g.DrawString(Text, SystemInformation.MenuFont,
SystemBrushes.ControlLightLight, x + 1, y + 1, _stringformat)
g.DrawString(ShortCut, SystemInformation.MenuFont,
SystemBrushes.ControlLightLight, Bounds.Right - shortcutwidth - 10 + 1,
Bounds.Top + 2 + 1, _stringformat)
End If
g.DrawString(Text, SystemInformation.MenuFont, New
SolidBrush(SystemColors.GrayText), x, y, _stringformat)
g.DrawString(ShortCut, SystemInformation.MenuFont, New
SolidBrush(SystemColors.GrayText), Bounds.Right - shortcutwidth - 10,
Bounds.Top + 2, _stringformat)
End If
End Sub
End Class

Public Class VSNetStyle : Implements MenuItemStyleDrawer


' El color de fondo de los menús
Shared bgcolor As Color = SystemColors.ControlLightLight
'//Color.FromArgb(246, 246, 246);
Dim ibgcolor As Color = SystemColors.Control
'SystemColors.ControlLight ' El color de la banda izquierda de los
menús '//Color.FromArgb(202, 202, 202);
Shared sbcolor As Color = Color.FromArgb(200, 215, 240) ' color de
fondo del elemento seleccionado ' Color.FromArgb(173, 173, 209)
Dim sbbcolor As Color = Color.FromArgb(60, 96, 192) ' Color
alrededor de la selección '0,0,128
Dim TEXTSTART As Integer = 20
'
Public Shared ReadOnly Property BackColor() As Color
Get
Return bgcolor
End Get
End Property
Public Shared ReadOnly Property SelectedBackColor() As Color
Get
Return sbcolor
End Get
End Property
'
Public Sub DrawCheckmark(ByVal g As Graphics, ByVal bounds As
Rectangle, ByVal selected As Boolean) Implements
MenuItemStyleDrawer.DrawCheckmark
ControlPaint.DrawMenuGlyph(g, New Rectangle(bounds.X + 2,
bounds.Y + 2, 14, 14), MenuGlyph.Checkmark)
'g.DrawRectangle(new Pen(sbbcolor), bounds.X + 1, bounds.Y + 1,
14 + 1, 14 + 1);
End Sub

Public Sub DrawIcon(ByVal g As Graphics, ByVal icon As Image, ByVal


bounds As Rectangle, ByVal selected As Boolean, ByVal enabled As Boolean,
ByVal ischecked As Boolean) Implements MenuItemStyleDrawer.DrawIcon
If (enabled) Then
If (selected) Then
ControlPaint.DrawImageDisabled(g, icon, bounds.Left + 2,
bounds.Top + 2, Color.Black)
g.DrawImage(icon, bounds.Left + 1, bounds.Top + 1)
Else
g.DrawImage(icon, bounds.Left + 2, bounds.Top + 2)
End If
Else
ControlPaint.DrawImageDisabled(g, icon, bounds.Left + 2,
bounds.Top + 2, SystemColors.HighlightText)
End If
End Sub

Public Sub DrawSeparator(ByVal g As Graphics, ByVal bounds As


Rectangle) Implements MenuItemStyleDrawer.DrawSeparator
Dim y As Integer = CType(bounds.Y + bounds.Height / 2, Integer)
g.DrawLine(New Pen(SystemColors.ControlDark), bounds.X +
SystemInformation.SmallIconSize.Width + 7, y, bounds.X + bounds.Width -
2, y)
End Sub

Public Sub DrawBackground(ByVal g As Graphics, ByVal bounds As


Rectangle, ByVal state As DrawItemState, ByVal toplevel As Boolean, ByVal
hasicon As Boolean) Implements MenuItemStyleDrawer.DrawBackground
Dim selected As Boolean = (state And DrawItemState.Selected) > 0

If (selected OrElse ((state And DrawItemState.HotLight) > 0))


Then
If (toplevel AndAlso selected) Then '// draw toplevel,
selected menuitem
g.FillRectangle(New SolidBrush(ibgcolor), bounds)
ControlPaint.DrawBorder3D(g, bounds.Left, bounds.Top,
bounds.Width, bounds.Height, Border3DStyle.Flat, Border3DSide.Top Or
Border3DSide.Left Or Border3DSide.Right)
Else '// draw menuitem, selected OR toplevel, hotlighted
g.FillRectangle(New SolidBrush(sbcolor), bounds)
g.DrawRectangle(New Pen(sbbcolor), bounds.X, bounds.Y,
bounds.Width - 1, bounds.Height - 1)
End If
Else
If (Not toplevel) Then '// draw menuitem, unselected
g.FillRectangle(New SolidBrush(ibgcolor), bounds)
bounds.X += 16 + 5
bounds.Width -= 16 + 5
g.FillRectangle(New SolidBrush(bgcolor), bounds)
Else
'// draw toplevel, unselected menuitem
g.FillRectangle(SystemBrushes.Control, bounds)

End If
End If
End Sub

Public Sub DrawMenuText(ByVal g As Graphics, ByVal bounds As


Rectangle, ByVal text As String, ByVal shortcut As String, ByVal enabled
As Boolean, ByVal toplevel As Boolean, ByVal state As DrawItemState)
Implements MenuItemStyleDrawer.DrawMenuText
Dim stringformat As StringFormat = New StringFormat
stringformat.HotkeyPrefix = CType(IIf(((state And
DrawItemState.NoAccelerator) > 0), HotkeyPrefix.Hide, HotkeyPrefix.Show),
HotkeyPrefix)
Dim textwidth As Integer = CType(g.MeasureString(text,
SystemInformation.MenuFont).Width, Integer)
Dim shortcutwidth As Integer = CType(g.MeasureString(shortcut,
SystemInformation.MenuFont).Width, Integer)

Dim x As Integer = CType(IIf(toplevel, bounds.Left +


(bounds.Width - textwidth) / 2, bounds.Left + TEXTSTART), Integer)
Dim y As Integer = bounds.Top + 2
Dim brush As Brush = Nothing
If (Not enabled) Then
brush = New SolidBrush(Color.FromArgb(120,
SystemColors.MenuText))
Else
brush = New SolidBrush(SystemColors.MenuText)
End If
g.DrawString(text, SystemInformation.MenuFont, brush, x, y,
stringformat)
g.DrawString(shortcut, SystemInformation.MenuFont, brush,
bounds.Right - shortcutwidth - 10, bounds.Top + 2, stringformat)
End Sub
End Class
'End Namespace
El código para C#
Este es el código original de RichMenuItem.cs en el que me basé para crear la
versión de Visual Basic, y lo publico porque en las versiones actuales de
SharpDevelop ya no se incluye.
Espero que te sea de utilidad, pero observa el copyright de la clase.
// RichMenuItem.cs
// Copyright (c) 2001 Mike Krueger
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA

using System;
using System.Drawing;
using System.Diagnostics;
using System.Drawing.Text;
using System.Drawing.Imaging;
using System.Windows.Forms;

//using SharpDevelop.Gui.Window;
//using SharpDevelop.Tool.Data;
//using SharpDevelop.Internal.ExternalTool;
//using SharpDevelop.Internal.Text;

namespace NCvs.Gui.Components {

public enum IconMenuStyle {


Standard,
Office2000,
VSNet
};

public interface MenuItemStyleDrawer


{
void DrawCheckmark(Graphics g, Rectangle bounds, bool
selected);
void DrawIcon(Graphics g, Image icon, Rectangle bounds,
bool selected, bool enabled, bool ischecked);
void DrawSeparator(Graphics g, Rectangle bounds);
void DrawBackground(Graphics g, Rectangle bounds,
DrawItemState state, bool toplevel, bool hasicon);
void DrawMenuText(Graphics g, Rectangle bounds, string
text, string shortcut, bool enabled, bool toplevel, DrawItemState state);
}

public class Office2000Style : MenuItemStyleDrawer


{
static int TEXTSTART = 20;

public void DrawCheckmark(Graphics g, Rectangle bounds,


bool selected)
{
ControlPaint.DrawMenuGlyph(g, new
Rectangle(bounds.X + 2, bounds.Y + 2, 14, 14), MenuGlyph.Checkmark);
}

public void DrawIcon(Graphics g, Image icon, Rectangle


bounds, bool selected, bool enabled, bool ischecked)
{
if (enabled) {
g.DrawImage(icon, bounds.Left + 2,
bounds.Top + 2);
} else
ControlPaint.DrawImageDisabled(g, icon,
bounds.Left + 2, bounds.Top + 2, SystemColors.Control);

if (selected)
ControlPaint.DrawBorder3D(g, bounds.Left,
bounds.Top, icon.Width + 3, icon.Height + 3, Border3DStyle.RaisedInner);
}

public void DrawSeparator(Graphics g, Rectangle bounds)


{
ControlPaint.DrawBorder3D(g, bounds.X, bounds.Y +
2, bounds.Width, 3, Border3DStyle.Etched, Border3DSide.Top);
}

public void DrawBackground(Graphics g, Rectangle bounds,


DrawItemState state, bool toplevel, bool hasicon)
{
bool selected = (state & DrawItemState.Selected) >
0;
if (selected ||((state & DrawItemState.HotLight) >
0)) {
if (toplevel) {
// g.FillRectangle(SystemBrushes.Highlight,
bounds);
ControlPaint.DrawBorder3D(g, bounds.Left,
bounds.Top, bounds.Width, bounds.Height, selected ?
Border3DStyle.SunkenOuter : Border3DStyle.RaisedInner, Border3DSide.All);
} else {
if (hasicon) {

g.FillRectangle(SystemBrushes.Menu, new Rectangle(bounds.X, bounds.Y,


bounds.X + SystemInformation.SmallIconSize.Width + 5, bounds.Height));
bounds.X +=
SystemInformation.SmallIconSize.Width + 5;
bounds.Width -=
SystemInformation.SmallIconSize.Width + 5;
}
g.FillRectangle(SystemBrushes.Highlight,
bounds);
}
} else {
if (toplevel) {

g.FillRectangle(SystemBrushes.Control, bounds);
} else {
g.FillRectangle(SystemBrushes.Menu,
bounds);
}
}
}

public void DrawMenuText(Graphics g, Rectangle bounds,


string text, string shortcut, bool enabled, bool toplevel, DrawItemState
state)
{
bool selected = (state & DrawItemState.Selected) >
0;
StringFormat stringformat = new StringFormat();
stringformat.HotkeyPrefix = ((state &
DrawItemState.NoAccelerator) > 0) ? HotkeyPrefix.Hide :
HotkeyPrefix.Show;
int shortcutwidth =
(int)(g.MeasureString(shortcut, SystemInformation.MenuFont).Width);
int textwidth = (int)(g.MeasureString(text,
SystemInformation.MenuFont).Width);
int x = toplevel ? bounds.Left + (bounds.Width -
textwidth) / 2: bounds.Left + TEXTSTART;

int y = bounds.Top + 2;
if (enabled) {
// normal draw
Color color = (selected && !toplevel) ?
Color.White : SystemColors.MenuText;
g.DrawString(text,
SystemInformation.MenuFont, new SolidBrush(color), x, y, stringformat);
g.DrawString(shortcut,
SystemInformation.MenuFont, new SolidBrush(color), bounds.Left + 130,
bounds.Top + 2, stringformat);
} else {
// disabled menuitem draw
if (!selected) {
g.DrawString(text,
SystemInformation.MenuFont, SystemBrushes.ControlLightLight, x + 1, y +
1, stringformat);
g.DrawString(shortcut,
SystemInformation.MenuFont, SystemBrushes.ControlLightLight, bounds.Right
- shortcutwidth - 10 + 1, bounds.Top + 2 + 1, stringformat);
}
g.DrawString(text,
SystemInformation.MenuFont, new SolidBrush(SystemColors.GrayText), x, y,
stringformat);
g.DrawString(shortcut,
SystemInformation.MenuFont, new SolidBrush(SystemColors.GrayText),
bounds.Right - shortcutwidth - 10, bounds.Top + 2, stringformat);
}
}
}

public class VSNetStyle : MenuItemStyleDrawer


{
static Color bgcolor = SystemColors.ControlLightLight;
//Color.FromArgb(246, 246, 246);
static Color ibgcolor = SystemColors.ControlLight;
//Color.FromArgb(202, 202, 202);

static Color sbcolor = Color.FromArgb(173, 173, 209);


static Color sbbcolor = Color.FromArgb( 0, 0, 128);

static int TEXTSTART = 20;

public void DrawCheckmark(Graphics g, Rectangle bounds,


bool selected)
{
ControlPaint.DrawMenuGlyph(g, new
Rectangle(bounds.X + 2, bounds.Y + 2, 14, 14), MenuGlyph.Checkmark);
}

public void DrawIcon(Graphics g, Image icon, Rectangle


bounds, bool selected, bool enabled, bool ischecked)
{
if (enabled) {
if (selected) {
ControlPaint.DrawImageDisabled(g, icon,
bounds.Left + 2, bounds.Top + 2, Color.Black);
g.DrawImage(icon, bounds.Left + 1,
bounds.Top + 1);
} else {
g.DrawImage(icon, bounds.Left + 2,
bounds.Top + 2);
}
} else
ControlPaint.DrawImageDisabled(g, icon,
bounds.Left + 2, bounds.Top + 2, SystemColors.HighlightText);
}

public void DrawSeparator(Graphics g, Rectangle bounds)


{
int y = bounds.Y + bounds.Height / 2;
g.DrawLine(new Pen(SystemColors.ControlDark),
bounds.X + SystemInformation.SmallIconSize.Width + 7, y, bounds.X +
bounds.Width - 2, y);
}

public void DrawBackground(Graphics g, Rectangle bounds,


DrawItemState state, bool toplevel, bool hasicon)
{
bool selected = (state & DrawItemState.Selected) >
0;

if (selected || ((state & DrawItemState.HotLight)


> 0)) {
if (toplevel && selected) { // draw
toplevel, selected menuitem
g.FillRectangle(new SolidBrush(ibgcolor),
bounds);
ControlPaint.DrawBorder3D(g, bounds.Left,
bounds.Top, bounds.Width, bounds.Height, Border3DStyle.Flat,
Border3DSide.Top | Border3DSide.Left | Border3DSide.Right);
} else { // draw menuitem, selected OR
toplevel, hotlighted
g.FillRectangle(new SolidBrush(sbcolor),
bounds);
g.DrawRectangle(new Pen(sbbcolor),
bounds.X, bounds.Y, bounds.Width - 1, bounds.Height - 1);
}
} else {
if (!toplevel) { // draw menuitem,
unselected
g.FillRectangle(new SolidBrush(ibgcolor),
bounds);
bounds.X += 16 + 5;
bounds.Width -= 16 + 5;
g.FillRectangle(new SolidBrush(bgcolor),
bounds);
} else {
// draw toplevel, unselected
menuitem

g.FillRectangle(SystemBrushes.Control, bounds);

}
}
}

public void DrawMenuText(Graphics g, Rectangle bounds,


string text, string shortcut, bool enabled, bool toplevel, DrawItemState
state)
{
StringFormat stringformat = new StringFormat();
stringformat.HotkeyPrefix = ((state &
DrawItemState.NoAccelerator) > 0) ? HotkeyPrefix.Hide :
HotkeyPrefix.Show;
int textwidth = (int)(g.MeasureString(text,
SystemInformation.MenuFont).Width);
int shortcutwidth =
(int)(g.MeasureString(shortcut, SystemInformation.MenuFont).Width);

int x = toplevel ? bounds.Left + (bounds.Width -


textwidth) / 2: bounds.Left + TEXTSTART;
int y = bounds.Top + 2;
Brush brush = null;
if (!enabled)
brush = new SolidBrush(Color.FromArgb(120,
SystemColors.MenuText));
else
brush = new
SolidBrush(SystemColors.MenuText);
g.DrawString(text, SystemInformation.MenuFont,
brush, x, y, stringformat);

g.DrawString(shortcut, SystemInformation.MenuFont,
brush, bounds.Right - shortcutwidth - 10, bounds.Top + 2, stringformat);
}
}

public class RichMenuItem : MenuItem


{
string shortcuttext = "";
StringFormat stringformat = new StringFormat();
Bitmap icon = null;

MenuItemStyleDrawer style = null;


IconMenuStyle menustyle = IconMenuStyle.VSNet;

int shortcuttextwidth;

public IconMenuStyle MenuStyle {


get {
return menustyle;
}
set {
switch (value) {
case IconMenuStyle.Office2000:
style = new
Office2000Style();
OwnerDraw = true;
break;
case IconMenuStyle.VSNet:
style = new VSNetStyle();
OwnerDraw = true;
break;
default:
style = null;
OwnerDraw = false;
break;
}
}
}

public string ShortcutText {


get {
return shortcuttext;
}
set {
shortcuttext = value;
}
}

public Bitmap Icon {


get {
return icon;
}
set {
icon = value;
}
}
public RichMenuItem()
{
}

public RichMenuItem(IconMenuStyle style, string name,


EventHandler handler, Shortcut shortcut) : this(style, name, handler)
{
this.Shortcut = shortcut;
}

public RichMenuItem(IconMenuStyle style, string name) :


base(name)
{
MenuStyle = style;
}

public RichMenuItem(IconMenuStyle style, string name,


EventHandler handler) : base(name, handler)
{
MenuStyle = style;
}

public RichMenuItem(IconMenuStyle style, string name,


MenuItem[] items) : base(name, items)
{
MenuStyle = style;
}

// public override MenuItem CloneMenu()


// {
// return (MenuItem)MemberwiseClone();
// }

protected override void OnMeasureItem(MeasureItemEventArgs


e)
{
base.OnMeasureItem(e);

// make shortcut text


if (Shortcut != Shortcut.None) {
string text = "";
int key = (int)Shortcut;
int ch = key & 0xFF;
if (((int)Keys.Control & key) > 0)
text += "Ctrl+";
if (((int)Keys.Shift & key) > 0)
text += "Shift+";
if (((int)Keys.Alt & key) > 0)
text += "Alt+";
if (ch >= (int)Shortcut.F1 && ch <=
(int)Shortcut.F12)
text += "F" + (ch -
(int)Shortcut.F1 + 1);
else
text += (char)ch;
shortcuttext = text;
}

if (menustyle != IconMenuStyle.Standard) {
if (Text == "-") {
e.ItemHeight = 8;
e.ItemWidth = 4;
return;
}
int textwidth =
(int)(e.Graphics.MeasureString(Text, SystemInformation.MenuFont).Width);
shortcuttextwidth =
(int)(e.Graphics.MeasureString(shortcuttext,
SystemInformation.MenuFont).Width);
textwidth += shortcuttextwidth;

e.ItemHeight = SystemInformation.MenuHeight;
if (Parent == Parent.GetMainMenu())
e.ItemWidth = textwidth - 5; // 5 is a
magic number :)
else
e.ItemWidth = Math.Max(160,
textwidth + 15);
}
}

protected override void OnSelect(EventArgs e)


{
base.OnSelect(e);
}

protected override void OnDrawItem(DrawItemEventArgs e)


{
base.OnDrawItem(e);
Graphics g = e.Graphics;
Rectangle bounds = e.Bounds;
bool selected = (e.State & DrawItemState.Selected)
> 0;
bool toplevel = (Parent == Parent.GetMainMenu());
bool hasicon = Icon != null;

style.DrawBackground(g, bounds, e.State, toplevel,


hasicon);
if (hasicon)
style.DrawIcon(g, Icon, bounds, selected,
Enabled, Checked);
else
if (Checked)
style.DrawCheckmark(g, bounds, selected);
if (Text == "-") {
style.DrawSeparator(g, bounds);
} else {
style.DrawMenuText(g, bounds, Text,
shortcuttext, Enabled, toplevel, e.State);
}
}
}
}

La autorización de Mike Krüger para publicar el código traducido a VB.NET sin


necesidad de usar el GPL:

Como notarás hace tiempo de esto... y hasta ahora no lo había publicado... en fin cosas de
las pocas neuronas que tengo, y si no llega a ser por una pregunta en los grupos de noticias,
pues ni me hubiese acordado, ya que tanto en Visual Basic 2005 como Visual C# 2005 se
incluye la posibilidad de usar iconos en los menús.

From: "Mike Krüger" <mike@icsharpcode.net>


To: "Guillermo 'guille'" <guille@costasol.net>
Sent: Wednesday, January 16, 2002 6:42 PM
Subject: Re: SharpDevelop

Hi

> And also I want to ask you if I can use the RichMenuItem class, (I
translate it
> to VB.NET and works fine), and I would like to publish a sample code using
that
> class. I have a site dedicated to VB (and soon to C#).

Sorry, I clicked send to fast :(

Yes you can use the RichMenuItem class in a sample without the GPL applied.
(thanx that you ask, I give code away, if people just >ask< :))

cya

You might also like