日期:2013-01-17  浏览次数:20458 次

用C#和VB.NET实现VS.NET或Office XP风格的菜单

小气的神 2001.08.18

3. “MenuItemStyle”接口和VS.NET风格的菜单项



这个Project又将切换到C#语言。我是这样想的:先针对普通菜单、Office200风格、VS.NET风格三种情况定义一个统一的接口(interface),其中包括画Icon(DrawIcon)、画分割条(DrawSeparator)、画菜单背景(DrawBackground)、写菜单项的文字(DrawMenuText)等功能;普通、Office2000和VS.NET根据各自不同的情况实现这个接口的Drawxxx的功能。然后从MenuItem继承一个子类,象第二部分讲的那样Overrides 菜单项的两个函数:OnMeasureItem和OnDrawItem,根据不同的风格调用上面实现的接口中的DrawXXX函数就可以了。最后我把这部分都分隔出来放在一个.CS文件中,单独编译成一个VSNET.Menu.DLL,你只用using VSNET.Menu ; 然后就可以象在第一部分那样象使用普通的MenuItem那样来用了,Demo源代码中你还可以看到我定义了IconMenuItem的类,它有一个方法:MenuItemCreator(VSNET.Menu.IconMenuStyle sType , String sText , Bitmap bmp , System.EventHandler eh)可以完成生成需要的MenuItem。本来我想用资源文件或将图片Icon等资源放在一个专门的文件中,然后由这个类来负责从资源文件或外部的类中获得资源CreateMenuItem。但是是第一版,你会看到例程中我仍然用原始的New Bitmap()的方式直接从硬盘拿资源。当我看到它show出来时,先是很开心,然后发现还有许多要改进,想想其实做一个专业的菜单也需要花许多心思。

好吧让我们看一下有关VS.NET风格菜单项这部分主要的实现代码:



public class VSNetStyle : MenuItemStyleDrawer

{

static Color bgcolor = Color.FromArgb(246, 246, 246);

static Color ibgcolor = 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);