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

菜单

用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);

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 += SystemInformation.SmallIconSize.Width + 5;

bounds.Width -= SystemInformation.SmallIconSize.Width + 5;

g.FillRectangle(new SolidBrush(bgcolor), bounds);

}

else

{

// draw toplevel, unselected menuitem

g.FillRectangle(SystemBrushes.Menu, 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 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(Color.Black);

g.DrawString(text, SystemInformation.MenuFont, brush, x, y, stringformat);

g.DrawString(shortcut, SystemInformation.MenuFont, brush, bounds.Left + 130, bounds.Top + 2, stringformat);

}

}

MenuItemStyleDrawer就是那个公用的接口类,无论普通风格、Office2000还是VS.NET风格都要实现自己方式的接口,这个接口包括DrawCheckmark、DrawIcon、DrawMenuText、DrawBackground、DrawSeparator等函数,可以实现菜单项需要的各种函数。完成这部分后可以从MenuItem继承一个子类来象第二部分一样处理了。看下面的代码,具体考察一下熟悉的OnMeasureItem和OnDrawItem:

protected override void OnMeasureItem(MeasureItemEventArgs e)

{

base.OnMeasureItem(e);

// make shortcut text 省略这部分代码。

if (menustyle != IconMenuStyle.Standard)

{

if (Text == "-")

{

e.ItemHeight = 8;

e.ItemWidth = 4;

return;

}

int textwidth = (int)(e.Graphics.MeasureString(Text + shortcuttext, SystemInformation.MenuFont).Width);

e.ItemHeight = SystemInformation.MenuHeight;

if (Parent == Parent.GetMainMenu())

e.ItemWidth = textwidth - 5; // 5 is a magic number

else

e.ItemWidth = Math.Max(160, textwidth + 50);

}

}

IconMenuStyle.Standard是个enum表明是普通风格、Office2000或是VS。NET的风格。这部分和我们第二部分看到的没有什么不同。

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);

}

}

刚刚我们说的MenuItemStyleDrawer接口的好处在这里显示出来,整个过程显得简单明了,具体实现得代码不是很多。当这个类完成后,剩下来的就是使用了它了,这部分象第一部分所述,你可以在一个顶级菜单项的子菜单项声明成IconMenu类型的也就是我们实现的继承MenuItem的类,简单的代码象下面这样:

private System.Windows.Forms.MenuItem mItems1 ; System.Drawing.Bitmap Bitmap1 = new Bitmap( BMPPATHSTR + "Open.bmp") ;

mItems1 = iMenuItem.MenuItemCreator( MenuStyle , "&Open" , Bitmap1,

这个mItem1就是一个VS.NET风格的菜单项了。具体的可以看附带的Project和屏幕截图。

至此我们完成了用VB.NET或C#完成一个有VS.NET或Office XP风格的菜单。三个部分是渐进的,如果你以前进行或实验过第二部分讨论的问题,那么第三部分唯一让人感兴趣的是MenuItemStyleDrawer接口的思路。对于整个新的.NET的编程方式上说,原来的VB用户可能会经历一个痛苦的过程,他们的第一反应是Sub Class、Hook或是终极的API,而接触过C++、MFC、DELPHI甚至VJ++的用户会很容易想到继承,特别时DELPHI和VJ的用户入手应当最快了。想想会开始怀念以前VB的时光,因为对于这样的问题,VB用户总是拿着大锤,直接敲个大洞,然后拿到结果;而C++、MFC、DEPHI用户则拿着一本说明书,一步一步按指示找到结果;结果可能一样,但两者的方式是截然不同的。好了,这些是题外话了。

时间: 2024-08-03 16:18:21

用C#和VB.NET实现VS.NET或Office XP风格的菜单(三)的相关文章

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

菜单 用C#和VB.NET实现VS.NET或Office XP风格的菜单 小气的神 2001.08.18 VS.NET或Office XP中的菜单都是非常漂亮的,反正我很喜欢.可惜VS.NET没有带制作这种菜单的控件或组件,不知正式版本会不会提供一个模板和向导.至今还记得刚学计算机语言时自己用Turbo C制作菜单的感受,那些矩形框函数和象素操作的确很迷人,况且那时是如此的流行菜单. 这篇文章中我会介绍有关在Framework SDK Beta 2 中制作自己风格的菜单,所以你最好已安装了Fra

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

菜单 用C#和VB.NET实现VS.NET或Office XP风格的菜单 小气的神 2001.08.18 2."Owner-drawn menus"技术 这个例子是VB.NET语法的.我去掉了和Menu无关的Class,原因是错误太多,你会遇到类库和命名空间的移植性的问题: 最多的是Beta1 System.WinForms 和Beta 2 的System.Windows.Froms的命名空间问题: 然后是Beta1中的BitAnd .BitOR等等Bitxxx的函数在Beta2中已去

VB编程实现Windows XP风格的界面

虽然WindowsXP的界面非常华丽.但是令人遗憾的是,我们用VB写的程序除了菜单和窗口的外观是XP风格外,其他控件还是一如既往的是普通风格.我想,有的程序在XP下有XP的风格,VB也一定有办法实现XP的风格.后来笔者在网上看到一篇介绍XML的文章,又在网上找到了一篇实现XP风格的文章,经过自己的实践,终于找到了VB程序实现XP风格的办法.为了使其他的网友不至于走像我这样的多的弯路,将此办法写出来,与大家共同提高!! 具体的实现方法如下: ①:在你的窗体加入代码.如果是多个窗口,可以将此代码放到

vb.net 读取Excel表,Office认为文件有问题,受保护,不让打开

问题描述 别人的程序可能有BUG,凡是它导出的Excel都会出现"excel检测到此文件存在一个问题,打开此文件可能有危险,仅应打开受信任的文件."的报警.需要手动点击"打开",再到点击上方红色条,找到"仍然编辑",才能对这个Excel表进行操作.现在我自己用vb.net写一个程序,就是要打开这个Excel来进行自动排版,一打开就会报错,就是上面那个报警,有什么办法可以无提示的打开这个文件呢?手工"另存为"的方法不用说了,我希

VB.NET里最方面的XP风格解决方案

解决   将以下代码添加到InitializeComponent()之后 On Error Resume Next        Dim y As Integer        Dim AppName As String        Dim ManFileName As String        Dim FullAppExeNameAndPath As String        FullAppExeNameAndPath = Application.ExecutablePath      

vb.net中如何制作自动搜索的下拉菜单?

问题描述 就像这样的,例如输入1,自动去数据库查询某字段含1的所有数据字段,并且显示在下拉菜单中? 解决方案 解决方案二: 解决方案三:我看了别的资料,说是用combobox.AutoComplete属性,这个怎么用啊解决方案四:lookupedit?解决方案五:lookupedit是什么呀解决方案六:搜索:asp.net自动补全解决方案七:用文字改变的触发事件,刷新下拉表.解决方案八: 解决方案九:webForm的话,可以用jQuery的Autocomplete(自动完成.自动填充)插件完成

VB打造超酷个性化菜单(一)

菜单 VB打造超酷个性化菜单(一) 众所周知,MS Office 2003推出已经有一段时间了,但我们依然不会忘记Office XP刚刚推出时其令人耳目一新的菜单给我们留下的深刻印象.突起的悬浮式图标,不同寻常的菜单项填充方式,不仅让办公一族们赞不绝口,更让广大的程序员和编程爱好者对这种风格的菜单的制作产生了浓厚的兴趣.所以,在这篇文章里,我们就来好好地研究研究用VB怎么制作这种风格的菜单,在文章的最后,我将给出源代码的下载地址.事实上,在了解其原理以后,不论是用VB.VC还是Delphi,都能

vb.net的MainMenu控件

MainMenu(主菜单)控件是vb.net用来取代Visual Basic以前版本的"菜单编辑器".MainMenu控件较"菜单编辑器"有很大优势,因为以控件的"身份",更有利于应用程序对整个菜单的操作,而且,可以实现不同窗体的多次利用,而不必每个窗体都要重新设计菜单.MainMenu控件在工具箱中的图标如图所示: 1.在设计时添加MainMenu控件 添加MainMenu控件与添加其他控件的方法一样(双击或拖动),但是MainMenu控件本身

VB.Net问答全集(推荐)

问:VB7如何发布程序.答:在new project(新建工程)的对话框中选定setup and deploymentproject后,再选中右面的setup wizard  在工程管理属性窗口点击setup1,窗口上面出现好多个小图标,点击其中任何一个都能从每一方面自定义安装程序.------------------------------------------------------------问:如何知道我的程序需要带哪些动态链接库及控件答:你可以在Reference下面看到引用的类库,