创意无极限,用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 运行一下,你会得到一个主菜单也有图标,各个菜单项的字体和底色都不同的菜单!这只是一个演示,但是最好不要在真正的软件中这样设计,菜单应该保持统一的风格。 这篇文章只是介绍一个修改菜单的基本方法,我希望大家能够举一反三,发挥自己的创造力,制作出自己的个性化菜单来!

|