创意无极限,用VB7制作您的个性化菜单
现代的软件开发,由于开发工具的大幅度进步,早已经让编程变得相当简单了,大家使用同样的工具,能不能写出好的程序来,在很大的程度上来说,已经不单单是技术的较量,而更多的是创意的竞争了。如何让用户对您的软件产生好感,我想除了过硬的技术以外,我们还需要一些新奇的东西,让用户有一种耳目一新的感觉!今天我就从软件界面中最常使用的菜单方面着手,教你制作一个个性化的菜单!
VB7中的菜单,如果没有对它编写过特殊的处理程序,虽然不能说难看,但是和现在流行的Office,XP等程序的菜单相比,实在是不够漂亮,如果不想让您的软件看上去象是上个世纪的作品,那么就开始学习编写新的菜单吧!
在VB7中,有两种生成菜单的方法,一种是让系统自动生成,一种是让程序按照一定的指定方式生成。前者可以不用编程,就生成菜单,但是这并不是我们想要的;所以我们选择后者。
好,第一步,我们先在窗体上面放上一个MainMenu控件吧!至于菜单的标题,你喜欢怎么写就怎么写,为了做个示范,我的菜单如下:
文件 MenuItem1
新建 MenuItem2
打开 MenuItem3
保存 MenuItem4
退出 MenuItem5
运行一下这个窗体,我们发现在“文件”的菜单下面出现了四个关于文件的菜单项。好,第一步成功了!但这仅仅只是第一步!接下来,在进行下面的讲解前,我们假设在您的手头上面有一些图标文件,它们是C:\file.ico, C:\new.ico, C:\open.ico, C:\save.ico, C:\exit.ico ,当然如果你手上没有,也可以用其他的图标暂时代替一下,只要能有效果就可以了!好了,既然我们不要程序自动生成菜单,那么我们把这些菜单项的OwnerDraw属性修改一下,在菜单的属性框中找到OwnerDraw,并且设置成True。(这个时候再运行的话,由于还没有写菜单的生成方式,我们将看不到菜单!)
继续以前,我还要先简单说一下这个菜单的生成原理,菜单的生成靠的时两个过程,一个过程叫作:MeasureItems,另一个过程叫作DrawItem。前者的作用是对菜单的大小进行测量(Measure),后者是在测量的基础上进行绘制(Draw),我们要做的事情就是重新写这两个受保护的事件,让菜单按我们的意愿绘制出来(显示出来)。
添加一个模块,下面的添加这两个事件的具体代码,代码对初学者来说可能有些长,但是通读一遍绝对有很多好处!!我会尽量给出所有的注释。
Imports System
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Text
Imports System.Windows.Forms
'以上是这个模块要用到的一些名字空间(只是一些前缀!注意,写了这些,仅仅是为了简化下面的书写,并没有其他任何实际功能。)
Module IconsMenuMain
Sub MeasureItems(ByVal EvMeasureItem As System.Windows.Forms.MeasureItemEventArgs , ByVal Mi As MenuItem, ByVal MyFont As Font)
'开始“测量菜单”的事件
Dim sf As StringFormat = New StringFormat()
'新建的字符格式对象
sf.HotkeyPrefix = HotkeyPrefix.Show
'指定与文本相关的热键前缀的显示类型。将其设置为显示
sf.SetTabStops(60, New Single() {0})
'第一个参数firstTabOffset表示
'文本行开头和第一个制表位之间的空格数。
'第二个参数tabStops()表示
'制表位之间的距离(以空格数表示)的数组。
EvMeasureItem.ItemHeight = 22 '设置项目的高度,最好是字体的高度!!
EvMeasureItem.ItemWidth=CInt(EvMeasureItem.Graphics.MeasureString (GetRealText(Mi), MyFont, 10000, sf).Width) + 10 '设置项目的宽度
sf.Dispose()
sf = Nothing '销毁对象
End Sub
说明:上面这个事件决定了菜单的大小,也就是菜单的高度和宽度,如果您有兴趣的话,可以将高度常数22,宽度中的附加值常数10 都变成事件参数!这样就有不同高度的菜单了!下面这个事件,我就将窗体菜单的渐变色的起始色和最终色变成了参数,用来分别控制每个菜单中的文字渐变底色!
Sub DrawItems(ByVal EvDrawItems As System.Windows.Forms.DrawItemEventArgs, ByVal Mi As MenuItem, ByVal m_Icon As Icon, ByVal StartColor As Color, ByVal EndColor As Color, ByVal MyFont As Font)
Dim br As Brush '定义刷子
Dim fDisposeBrush As Boolean '是否销毁刷子的标志
If Not m_Icon Is Nothing Then
'如果没有图标
If Not Mi.Checked Then
'无论是否菜单项目被选择了,都先画图标,尽管后者什么都没有EvDrawItems.Graphics.DrawIcon(m_Icon, EvDrawItems.Bounds.Left + 2, EvDrawItems.Bounds.Top + 2)
Else
EvDrawItems.Graphics.DrawIcon(m_Icon, EvDrawItems.Bounds.Left + 2, EvDrawItems.Bounds.Top + 2)
Dim nPen As System.Drawing.Pen
If Not Mi.Enabled Then
nPen = New Pen(Color.DarkGray) '如果可用,就填充颜色DarkGray
Else
nPen = New Pen(Color.Gray) '不然用颜色Gray
End If
EvDrawItems.Graphics.DrawRectangle(nPen,1,EvDrawItems.Bounds.Top, 20, 20)
EvDrawItems.Graphics.DrawRectangle(nPen, 3, EvDrawItems.Bounds.Top + 2, 16, 16)
'画上两个框,两个框构成一个“回“字型
End If
Else
'如果有图标
If Mi.Checked Then '如果菜单处于复选状态
Dim nPen As System.Drawing.Pen 新建一个画笔对象
If Not Mi.Enabled Then 根据是否可用决定画笔颜色
nPen = New Pen(Color.DarkGray)
Else
nPen = New Pen(Color.Gray)
End If
EvDrawItems.Graphics.DrawRectangle(nPen, 1,EvDrawItems.Bounds.Top, 20, 20)
'有图标,同时被选中,则只要画“回“字型中较大的一个框
Dim Pnts() As Point
ReDim Pnts(2) '这三个点就是一个“勾“的位置
Pnts(0) = New Point(15, EvDrawItems.Bounds.Top + 6)
Pnts(1) = New Point(8, EvDrawItems.Bounds.Top + 13)
Pnts(2) = New Point(5, EvDrawItems.Bounds.Top + 10)
'根据是否可用来决定画“勾“的颜色,并且画上“勾”
当然你可以根据需要来创造您自己菜单复选的图形
If Mi.Enabled Then
EvDrawItems.Graphics.DrawLines(New Pen(Color.Black), Pnts)
Else
EvDrawItems.Graphics.DrawLines(New Pen(Color.Gray), Pnts)
End If
End If
End If
Dim rcBk As Rectangle = EvDrawItems.Bounds
rcBk.X += 24 '先获得一个和菜单一样大小的矩形,然后将矩形的X方向长度缩短,缩短的大小就是图标的大小,以后将以这个矩形作为菜单文字背景底色的填充范围
'根据菜单项目是否被选中来决定是否使用颜色渐变刷子,
'如果是则设置刷子的颜色,同时将是否销毁刷子的标志设置为真
If CBool(EvDrawItems.State And DrawItemState.Selected) Then
br = New LinearGradientBrush(rcBk, StartColor, EndColor, 0)
设置起始色和最终色
fDisposeBrush = True ‘设置刷子销毁标志
Else
br = SystemBrushes.Control ‘这个颜色是系统的默认
End If
'画上渐变的菜单文字底色
EvDrawItems.Graphics.FillRectangle(br, rcBk)
If fDisposeBrush Then br.Dispose() '前面使用New方法新建的渐变颜色刷子的实例要销毁,但是前面的声明还是有效的
br = Nothing '将整个刷子暂时清空
Dim sf As StringFormat = New StringFormat()
sf.HotkeyPrefix = HotkeyPrefix.Show
'指定与文本相关的热键前缀的显示类型。将其设置为显示
sf.SetTabStops(60, New Single() {0})
'第一个参数firstTabOffset表示
'文本行开头和第一个制表位之间的空格数。
'第二个参数tabStops()表示
'制表位之间的距离(以空格数表示)的数组。
If Mi.Enabled Then '根据菜单是否可用来决定图像刷子的颜色
br = New SolidBrush(EvDrawItems.ForeColor)
Else
br = New SolidBrush(Color.Gray)
End If
'在菜单上面写字
EvDrawItems.Graphics.DrawString(GetRealText(Mi),MyFont,br,EvDrawItems.Bounds.Left + 25, EvDrawItems.Bounds.Top + 2, sf)
br.Dispose()
br = Nothing
sf.Dispose()
sf = Nothing
End Sub
Function GetRealText(ByVal Mi As MenuItem) As String
这个事件是用来获得菜单文本的
Dim s As String = Mi.Text '获得菜单原始文本
If Mi.ShowShortcut And Mi.Shortcut <> Shortcut.None Then
Dim k As Keys = CType(Mi.Shortcut, Keys)
'如果有菜单快捷键就让菜单文本加上快捷键文本
s = s & Convert.ToChar(9) & TypeDescriptor.GetConverter(GetType(Keys)).ConvertToString(k)
End If
Return s
End Function
说明:当然您可以让菜单的文本变成任何您想要的文本!
End Module
好了,最后一步就要看看我们的实际效果了,在原来的窗体上写上代码吧!!
下面我们以“美化”第一,第二个菜单项为例子,当然,一般主菜单不应该有图标的。看懂了以后,各位按照自己的想象力来画自己的菜单好了。
Private Sub MenuItem1_MeasureItem(ByVal sender As Object, ByVal e As System.Windows.Forms.MeasureItemEventArgs) Handles MenuItem1.MeasureItem
第一个测量事件 ,特别注意“Handles“标志 !
Dim MyFont As New System.Drawing.Font("Arial", 8) ‘定义一个你喜欢的字体
MeasureItems(e, MenuItem1, Myfont)
End Sub
Private Sub MenuItem1_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles MenuItem1.DrawItem
Dim Ic As New Icon("C:\file.ico") ‘定义一个您喜欢的图标
Dim MyFont As New System.Drawing.Font("Arial", 8) ‘这个字体最好和前面保持一致,当然如果您愿意,也可以在前面一种字体的确定范围用新字体写字,但是字体最好不要设置得太过火了,不然可能有意想不到的后果!
DrawItems(e, MenuItem2, Ic, Color.Blue, Color.Yellow, Myfont)
End Sub
Private Sub MenuItem2_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles MenuItem2.DrawItem
e.Graphics.CompositingQuality=Drawing.Drawing2D.CompositingQuality.HighQuality
Dim Ic As New Icon("C:\open.ico")
Dim MyFont As New System.Drawing.Font("Arial", 14)
DrawItems(e, MenuItem2, Ic, Color.Tomato, Color.LavenderBlush, MyFont)
End Sub
Private Sub MenuItem2_MeasureItem(ByVal sender As Object, ByVal e As System.Windows.Forms.MeasureItemEventArgs) Handles MenuItem2.MeasureItem
Dim MyFont As New System.Drawing.Font("Arial", 14)
MeasureItems(e, MenuItem2, MyFont)
End Sub
运行一下,你会得到一个主菜单也有图标,各个菜单项的字体和底色都不同的菜单!这只是一个演示,但是最好不要在真正的软件中这样设计,菜单应该保持统一的风格。
这篇文章只是介绍一个修改菜单的基本方法,我希望大家能够举一反三,发挥自己的创造力,制作出自己的个性化菜单来!