如何在Visual C#中自绘菜单
作者:Cryingwind
下载本文示例代码
当用户点击程序的主菜单项,下拉菜单弹出时,windows会对该下拉菜单的每个菜单项触发两个消息,WM_DRAWITEM和 WM_MEASUALITEM。前一个用来处理对菜单项的绘图任务,后一个当需要知道菜单项尺寸时发生。当鼠标在菜单项中移动时,如从项A移到项B,则同 样对A、B触发该消息。
本程序示例如何绘制带位图背景的菜单和类似QQ风格的菜单。首先准备两副位图,向窗体中添加MainMenu和ImageList组件,编辑 MainMenu组件使之有一定数量菜单项,编辑ImageList组件使之有一定数量小图标(属性窗口,点击image栏右侧的小按钮即可)。由于 VC#里面使用资源文件比较复杂,本例直接从文件读取算球。
在VC#里面,为任意一个菜单项指定处理函数(选定一个菜单项,到属性窗口的事件列表的DrawItem和MeasualItem栏右边双击即可快速完 成),并把其他处于同一下拉菜单的菜单项的处理函数设为以上相应的函数(选定一个菜单项,到属性窗口的事件列表的DrawItem和 MeasualItem栏,电机右栏的下拉小三角形选择即可)。
运行效果见下图:
编写方法及详细解释见以下代码:
private Bitmap bmp,bmp1;//用来装载菜单的背景和左侧条图片
string str;
Pen pen1,pen2;
Rectangle rect;
private void Form1_Load(object sender, System.EventArgs e)(完)
{//在窗体初始化时候初始化一些变量
bmp=new Bitmap("bitch.bmp",false);
bmp1=new Bitmap("10.bmp",false);
pen1=new Pen(Color.White);
pen2=new Pen(Color.Gray);
rect=new Rectangle(0,0,0,0);
}
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{//释放
bmp.Dispose();
bmp1.Dispose();
pen1.Dispose();
pen2.Dispose();
}
//上面右侧图所示菜单的绘制函数
private void menuItem2_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
if((e.State & DrawItemState.Selected) == DrawItemState.Selected)
{//判断鼠标是否正处在本菜单项上面,若是则用蓝色条加亮显式
//由于e.State是复合值,所以不能直接用e.State == DrawItemState.Selected判断
e.Graphics.FillRectangle(Brushes.Blue, e.Bounds);
}
else//用背景图片的合适区域绘制菜单背景
e.Graphics.DrawImage(bmp,e.Bounds,e.Bounds.X,e.Bounds.Y,e.Bounds.Width,e.Bound
s.Height,GraphicsUnit.Pixel );
str=((MenuItem)sender).Text;
e.Graphics.DrawString(str,e.Font,Brushes.White,e.Bounds.X+8,e.Bounds.Y+4);//绘制文字
}
//上面左侧图所示菜单的绘制函数
private void menuItem10_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
str=((MenuItem)sender).Text;
if((e.State & DrawItemState.Selected) == DrawItemState.Selected)
{//仿制QQ菜单的效果,如果鼠标移动到一个菜单项,则显式两个矩形,一个凸,一个
//凹,前一个凸的矩形里面显示一个小图表,后一个凹矩形里面显示菜单文字
rect.X=e.Bounds.X+22;
rect.Y=e.Bounds.Y+1;
rect.Width=17;
rect.Height=20;
DrawBevel(rect,e.Graphics,true);//true表示绘制凸矩形
rect.X+=19;
rect.Width=e.Bounds.Right-1-rect.X;
DrawBevel(rect,e.Graphics,false);//false表示绘制凹矩形
}
else
{//绘制菜单左边的蓝色长条图片
e.Graphics.DrawImage(bmp1,
e.Bounds,
e.Bounds.X,
e.Bounds.Y,
e.Bounds.Width,
e.Bounds.Height,
GraphicsUnit.Pixel);
rect=e.Bounds;
rect.X+=21;
//用系统默认的背景色绘制菜单项目
e.Graphics.FillRectangle(new SolidBrush(Color.FromKnownColor(KnownColor.Control)),rect);
}
if(str!="-")//判断菜单项是否分隔符,分隔符就是文字为一个短横杆,这和vc++60不同
{
//若不是,则绘制小图标和文字
imageList1.Draw(e.Graphics,e.Bounds.X+23,e.Bounds.Y+4,((MenuItem)sender).Index);
e.Graphics.DrawString(str,e.Font,Brushes.Black,e.Bounds.X+45,e.Bounds.Y+4);
}
else
{//若是分隔符,则绘制一个高度为1的矩形
rect=e.Bounds;
rect.X+=22;
rect.Y+=2;
rect.Height=1;
DrawBevel(rect,e.Graphics,false);
}
}