用c#绘制Office2003样式的菜单

我的方法是重写MenuItem类,在写的过程中发现用GDI+实际测量出来的文本的大小不是很准确,还有文本也不能很好对齐,固在代码里可以时常看到很多多加上去的数字.我想原理就不用我讲了吧,下面的代码注释的很
清楚了:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace OfficeMenu
{
 /// <summary>
 /// Class1 的摘要说明。
 /// </summary>
 public class OfficeMenuItem:MenuItem
 {
  public OfficeMenuItem(bool IsApplyOfficeMenu,string ItemText)
  {
   if(IsApplyOfficeMenu)
   {
    this.Text=ItemText;
    this.OwnerDraw=true;
    font=new Font("宋体",9f,GraphicsUnit.Point);
   }
   else
   {
    this.Text=ItemText;
    this.OwnerDraw=false;
   }
  }

  private Font font;
  private StringFormat strFormat=new StringFormat();
  private string ItemText="";
  private string iconPath="";

  //定义绘制的时候的各种笔刷
  private LinearGradientBrush TopMenuHostLightBrush;
  private SolidBrush TopMenuDefaultBrush;
  private SolidBrush FontDefaultBrush;
  private LinearGradientBrush TopMenuSelectedBrush;
  private SolidBrush MenuDefaultBrush;
  private SolidBrush MenuDefaultSelectedBrush;
  private SolidBrush MenuCheckBrush;
  private LinearGradientBrush MenuSideBarBrush;
  private SolidBrush MenuDefaultGrayedBrush;
  //定义绘制的时候所需的各种线条
  private Pen TopMenuPen;
  private Pen MenuDefaultPen;
  //定义需要的矩形结构
  private Rectangle SideBarRect;
  private Rectangle CheckedRect;
  private Rectangle TopMenuRect;
  private Rectangle ShortcutRect;

 

  //定义图标
  public string IconPath
  {
   get
   {
    return iconPath;
   }
   set
   {
    iconPath=value;
   }
  }

  //判断菜单是否是顶级菜单
  private bool CheckIsTop()
  {
   if(typeof(MainMenu)==this.Parent.GetType())
   {
    return true;
   }
   else
   {
    return false;
   }
  }
  //获取菜单的快捷键
  private string GetShortCut()
  {
   string shortcut="";
   try
   {
    if(this.ShowShortcut==true && (!this.IsParent) && (!(this.Shortcut==Shortcut.None)))
    {
     shortcut=this.Shortcut.ToString();
     shortcut=shortcut.Replace("Ctrl","Ctrl+");
     shortcut=shortcut.Replace("Alt","Alt+");
     shortcut=shortcut.Replace("Shift","Shift+");
    }
   }
   catch
   {
    return "";
   }
   return shortcut;
  }
  //重写测量函数
  protected override void OnMeasureItem(MeasureItemEventArgs e)
  {
   base.OnMeasureItem (e);

   try
   {
    ItemText=this.Text;
    SizeF SizeMenuText;
    if(this.ItemText=="-") //设置分割线的高度
    {
     e.ItemHeight=5;
     return;
    }

    string getedShortcut=this.GetShortCut();
    if(!this.CheckIsTop()) //如果不是顶级菜单
    {
     SizeMenuText=e.Graphics.MeasureString(ItemText+"".PadRight(4,' ')+getedShortcut,this.font);
     e.ItemWidth=Convert.ToInt32(SizeMenuText.Width)+26;
    }
    else
    {
     SizeMenuText=e.Graphics.MeasureString(ItemText,this.font);
     e.ItemWidth=Convert.ToInt32(SizeMenuText.Width)-4;
    }
    if(this.Visible)
    {
     e.ItemHeight=Convert.ToInt32(SizeMenuText.Height)+6;
    }
    else
    {
     e.ItemHeight=0;
    }
    
   }
   catch
   {
    e.ItemHeight=20;
    e.ItemWidth=80;
   }
  }
  //重写绘图函数
  protected override void OnDrawItem(DrawItemEventArgs e)
  {
   if(this.Visible)
   {
    base.OnDrawItem (e);
    Rectangle MenuRect=e.Bounds;
    ItemText=this.Text;
    Graphics g=e.Graphics;

    //绘制边框时需要的特殊矩形
    SideBarRect=new Rectangle(MenuRect.X,MenuRect.Y,25,MenuRect.Height);
    //绘制选择框时需要的矩形
    CheckedRect=new Rectangle(MenuRect.X+1,MenuRect.Y+1,24,MenuRect.Height-2);
    //绘制顶菜单时需要的矩形
    TopMenuRect=new Rectangle(MenuRect.X+1,MenuRect.Y+3,MenuRect.Width,MenuRect.Height);
    //绘制shortcut用到的矩形
    ShortcutRect=new Rectangle(MenuRect.X,MenuRect.Y+4,MenuRect.Width-10,MenuRect.Height);

    //定义绘制的时候的各种笔刷
    TopMenuHostLightBrush=new LinearGradientBrush(MenuRect,Color.White,Color.FromArgb(220,134,56),90f); //顶级菜单发生HOTLIGHT 时显示的颜色
    TopMenuDefaultBrush=new SolidBrush(SystemColors.Control); //顶级菜单默认的颜色
    FontDefaultBrush=new SolidBrush(Color.Black); //字体默认的颜色
    TopMenuSelectedBrush=new LinearGradientBrush(MenuRect,Color.White,Color.FromArgb(95,109,126),90f); //顶级菜单选中时的颜色
    MenuDefaultBrush=new SolidBrush(Color.White); //默认菜单的颜色
    MenuDefaultSelectedBrush=new SolidBrush(Color.FromArgb(247,218,157)); //菜单选中时的颜色
    MenuCheckBrush=new SolidBrush(Color.FromArgb(225,143,70)); //当菜单CHECKED属性为真的时显示的颜色
    MenuSideBarBrush=new LinearGradientBrush(SideBarRect,Color.White,Color.FromArgb(149,160,174),0f);//绘制侧栏
    MenuDefaultGrayedBrush=new SolidBrush(Color.FromArgb(105,105,105));//菜单不可用时
    //定义绘制的时候所需的各种线条
    TopMenuPen=new Pen(Brushes.Black,1f);  //顶级菜单的边框
    MenuDefaultPen=new Pen(new SolidBrush(Color.FromArgb(60,60,115)),1f); //正常选择时的边框

    //开始绘制****************************************************
    if(this.CheckIsTop() && this.ItemText!="-") //如果是顶级菜单
    {
     bool IsDraw=false;//定义一个变量保证正常显示的只绘制一次 避免浪费资源
     strFormat.Alignment=StringAlignment.Center;
     if(IsDraw==false) //绘制正常显示时的图像
     {
      g.FillRectangle(TopMenuDefaultBrush,MenuRect);
      g.DrawString(ItemText,this.font,FontDefaultBrush,TopMenuRect,strFormat);
     }

     //绘制HOTLIGHT时的图像
     if((e.State & DrawItemState.HotLight)==DrawItemState.HotLight)  //突出显示时
     {
      g.FillRectangle(TopMenuHostLightBrush,MenuRect);
      g.DrawRectangle(TopMenuPen,MenuRect.X,MenuRect.Y,MenuRect.Width-1,MenuRect.Height-1);
      g.DrawString(ItemText,this.font,FontDefaultBrush,TopMenuRect,strFormat);
      IsDraw=true;
     }
     //绘制菜单选中时的图像
     if((e.State & DrawItemState.Selected)==DrawItemState.Selected)
     {
      g.FillRectangle(TopMenuSelectedBrush,MenuRect);
      g.DrawRectangle(TopMenuPen,MenuRect.X,MenuRect.Y,MenuRect.Width-1,MenuRect.Height-1);
      g.DrawString(ItemText,this.font,FontDefaultBrush,TopMenuRect,strFormat);
      IsDraw=true;
     }
    }
    else  //非顶级菜单时
    {
     if(this.ItemText!="-")
     {
      bool IsDraw=false;
      if(IsDraw==false) //正常显示时
      {
       g.FillRectangle(MenuDefaultBrush,MenuRect);
       g.FillRectangle(MenuSideBarBrush,MenuRect.X,MenuRect.Y,25,MenuRect.Height);
       g.DrawString(ItemText,this.font,FontDefaultBrush,MenuRect.X+26,MenuRect.Y+4);
       //绘制shortcut
       string shortcut=this.GetShortCut();
       strFormat.Alignment=StringAlignment.Far;
       g.DrawString(shortcut,this.font,FontDefaultBrush,ShortcutRect,strFormat);
       //绘制图标
       this.DrawIcon(g);
      }

      if((e.State & DrawItemState.Selected)==DrawItemState.Selected) //选中时
      {
       this.DrawItem_Selected(g,MenuRect,ItemText);
       IsDraw=true;
      }

      if((e.State & DrawItemState.Grayed)==DrawItemState.Grayed) //不可用时
      {
       g.DrawString(ItemText,this.font,MenuDefaultGrayedBrush,MenuRect.X+26,MenuRect.Y+4);
       IsDraw=true;
      }

      if(!this.IsParent)
      {
       if((e.State & DrawItemState.Checked)==DrawItemState.Checked) //选择时
       {
        g.FillRectangle(MenuCheckBrush,CheckedRect);
        g.DrawRectangle(new Pen(Brushes.Black,1f),MenuRect.X+1,MenuRect.Y+1,23,MenuRect.Height-3);
        g.DrawString("√",this.font,FontDefaultBrush,MenuRect.X+3,MenuRect.Y+4);
        IsDraw=true;
       }

       if(this.Checked==true && ((e.State & DrawItemState.Selected)==DrawItemState.Selected)) //选中且Checked属性为真时
       {
        g.FillRectangle(new SolidBrush(Color.FromArgb(255,91,91)),CheckedRect);
        g.DrawRectangle(new Pen(Brushes.Black,1f),MenuRect.X+1,MenuRect.Y+1,23,MenuRect.Height-3);
        g.DrawString("√",this.font,FontDefaultBrush,MenuRect.X+3,MenuRect.Y+4);
        IsDraw=true;
       }
      }
     }
     else //画分割线
     {
      SolidBrush PartitionLineBrush=new SolidBrush(Color.FromArgb(128,128,128));
      Pen PartitionPen=new Pen(PartitionLineBrush,1f);
      g.FillRectangle(MenuDefaultBrush,MenuRect);
      g.FillRectangle(MenuSideBarBrush,MenuRect.X,MenuRect.Y,25,MenuRect.Height);
      g.DrawLine(PartitionPen,new Point(MenuRect.X+27,MenuRect.Y+2),new Point(MenuRect.X+27+(MenuRect.Width-26),MenuRect.Y+2));
     }


    }
   }
  }

  //画图标
  private void DrawIcon(Graphics g)
  {
   if(this.CheckIsTop()==false && this.IconPath!="" && this.IsParent==false && this.Checked==false)
   {
    try
    {
     Bitmap iconImage=new Bitmap(this.IconPath);
     int imageWidth=iconImage.Width;
     int imageHeight=iconImage.Height;
     if(imageWidth<=CheckedRect.Width && imageHeight<=CheckedRect.Height)
     {
      int ImageRecWidthMistake=CheckedRect.Width-imageWidth;
      float Mistake_2=(float)ImageRecWidthMistake/2f;
      g.DrawImage(iconImage,CheckedRect.X+(int)Mistake_2,CheckedRect.Y,imageWidth,imageHeight);
     }
     else
     {
      g.DrawImage(iconImage,CheckedRect);
     }
    }
    catch
    {
     throw new IconNotFindException("不能创建图标,可能是路径不能也可能是不支持此格式");
    }
   }
  }
  //由于再绘制的过程中选中的动作时需要执行两次一样的代码 固在这里用了一个函数
  private void DrawItem_Selected(Graphics g,Rectangle rec,string itemtext)
  {
   SolidBrush tmpBrush;
   if(this.Enabled)
   {
    tmpBrush=FontDefaultBrush;
   }
   else
   {
    tmpBrush=MenuDefaultGrayedBrush;
   }

   //正常显示
   g.FillRectangle(MenuDefaultSelectedBrush,rec);
   g.DrawRectangle(MenuDefaultPen,rec.X,rec.Y,rec.Width-1,rec.Height-1);
   g.DrawString(itemtext,this.font,tmpBrush,rec.X+26,rec.Y+4);

   //显示shortcut
   string shortcut=this.GetShortCut();
   strFormat.Alignment=StringAlignment.Far;
   g.DrawString(shortcut,this.font,tmpBrush,ShortcutRect,strFormat);
   //画图标
   this.DrawIcon(g);
  }
 }


 //自定义异常
 public class IconNotFindException:ApplicationException
 {
  public IconNotFindException(string message)
   :base(message)
  {
  }
 }
}

posted @ 2008-08-20 11:40  kin2321  阅读(312)  评论(0编辑  收藏  举报