菜单绘制项的状态DrawItemEventArgs.state

在学习之前先明白几个概念:

一、NoAccelerator  没有键盘加速键,也就是俗称的“快捷键”;如,Ctrl+C,Ctrl+V等我们熟悉的快捷键就是键盘加速键;(可参照 https://blog.csdn.net/u013678930/article/details/49812667)

if(e.state==(DrawItemState.NoAccelerator|DrawItemState.NoFocusRect))//当绘制项没有键盘加速键和焦点可视化提示时;(可参照 https://blog.csdn.net/hhhhhhhhhhwwwwwwwwww/article/details/105641386)

二、Selected – 鼠标悬停在项目上;而checked则是指选中项目;(可参照 https://blog.bossma.cn/dotnet/winform-combobox-drawitem/)

---------------------------------------------------------------------------------------------------------

下面正式开始分析

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Drawing;
  6 using System.Windows.Forms;
  7 using System.Drawing.Text;
  8 
  9 namespace OwnerDrawMenu
 10 {
 11     class OwnerDrawMenu:Form
 12     {
 13         const int iFontPointSize = 18;  //用于菜单项目
 14         MenuItem miFacename;
 15 
 16         static void Main(string[] args)
 17         {
 18             Application.Run(new OwnerDrawMenu());
 19         }
 20         public OwnerDrawMenu()
 21         {
 22             Text = "Owner Draw Menu";
 23 
 24             //Top Level items
 25             Menu = new MainMenu();
 26             Menu.MenuItems.Add("&Facename");
 27 
 28             //子菜单项的内容
 29             string[] astrText = { "&Times New Roman","&Arial","&Courier New"};
 30             MenuItem[] ami = new MenuItem[astrText.Length];
 31 
 32             EventHandler ehOnClick = new EventHandler(MenuFacenameOnClick);
 33             MeasureItemEventHandler ehOnMeasureItem =
 34                 new MeasureItemEventHandler(MenuFacenameOnMeasureItem);
 35             DrawItemEventHandler ehOnDrawItem =
 36                 new DrawItemEventHandler(MenuFacenameOnDrawItem);
 37 
 38             for (int i = 0; i < ami.Length; i++)
 39             {
 40                 ami[i] = new MenuItem(astrText[i]);
 41                 ami[i].OwnerDraw = true;
 42                 ami[i].RadioCheck = true;
 43                 ami[i].Click += ehOnClick;
 44                 ami[i].MeasureItem += ehOnMeasureItem;
 45                 ami[i].DrawItem += ehOnDrawItem;
 46             }
 47             miFacename = ami[0];
 48             miFacename.Checked = true;
 49 
 50             Menu.MenuItems[0].MenuItems.AddRange(ami);
 51         }
 52 
 53         void MenuFacenameOnClick(object obj, EventArgs ea)
 54         {
 55             miFacename.Checked = false;
 56             miFacename = (MenuItem)obj;
 57             miFacename.Checked = true;
 58 
 59             Invalidate();
 60         }
 61 
 62         void MenuFacenameOnMeasureItem(object obj, MeasureItemEventArgs miea)
 63         {
 64             MenuItem mi = (MenuItem)obj;
 65             Font font = new Font(mi.Text.Substring(1),iFontPointSize);
 66 
 67             StringFormat strfmt = new StringFormat();
 68             strfmt.HotkeyPrefix = HotkeyPrefix.Show;
 69 
 70             SizeF sizef = miea.Graphics.MeasureString(mi.Text,font,1000,strfmt);
 71 
 72             miea.ItemWidth = (int)Math.Ceiling(sizef.Width);
 73             miea.ItemHeight = (int)Math.Ceiling(sizef.Height);
 74 
 75             miea.ItemWidth += SystemInformation.MenuCheckSize.Width * 
 76                                 miea.ItemHeight / 
 77                                     SystemInformation.MenuCheckSize.Height;
 78             miea.ItemWidth -= SystemInformation.MenuCheckSize.Width;
 79         }
 80 
 81         void MenuFacenameOnDrawItem(object obj, DrawItemEventArgs diea)
 82         {
 83             MenuItem mi = (MenuItem)obj;
 84             Graphics grfx = diea.Graphics;
 85             Brush brush;
 86 
 87             //创建字体和格式
 88             Font font = new Font(mi.Text.Substring(1),iFontPointSize);
 89             StringFormat strfmt = new StringFormat();
 90             strfmt.HotkeyPrefix = HotkeyPrefix.Show;
 91 
 92             //计算选择标记和文字矩形
 93             Rectangle rectCheck = diea.Bounds;
 94 
 95             rectCheck.Width = SystemInformation.MenuCheckSize.Width * rectCheck.Height / SystemInformation.MenuCheckSize.Height;
 96             Rectangle rectText = diea.Bounds;
 97             rectText.X += rectCheck.Width;
 98 
 99             //绘制
100             diea.DrawBackground();
101             if ((diea.State & DrawItemState.Checked) != 0)
102                  ControlPaint.DrawMenuGlyph(grfx,rectCheck,MenuGlyph.Arrow);   //此行代码为绘制菜单前的三角形“箭头”
103 
104             //测试diea.state
105             Console.WriteLine("diea.state is {0}",diea.State);
106             Console.WriteLine("(diea.State & DrawItemState.Checked) is {0}", (diea.State & DrawItemState.Checked));
107             
108             if ((diea.State & DrawItemState.Checked) != 0)
109             
110                 brush = new SolidBrush(Color.Red);              //如果选中菜单的某一项内容,则此项内容的文字就变为红色;
111             else
112                 brush = new SolidBrush(Color.Yellow);           //未选中的其它菜单项内容,其文字就为黄色;
113 
114             grfx.DrawString(mi.Text,font,brush,rectText,strfmt);
115         }
116 
117         protected override void OnPaint(PaintEventArgs pea)
118         {
119             Graphics grfx = pea.Graphics;
120             Font font = new Font(miFacename.Text.Substring(1),12);
121             StringFormat strfmt = new StringFormat();
122             strfmt.Alignment = strfmt.LineAlignment = StringAlignment.Center;
123 
124             grfx.DrawString(Text,font,new SolidBrush(ForeColor),0,0);
125         }
126     }
127 }

运行的完整效果如下:

 

 关闭后,使用调试模式,可以看到,程序按照循环次数,依次对MenuFacenameOnDrawItem函数进行了三次循环调用,具体如下:

 

以上是调试后进入MenuFacenameOnDrawItem函数,第一次循环至110行产生的效果图;

继续在MenuFacenameOnDrawItem函数内运行,结束后会开始第二次循环,如下:

第二次循环后,可见diea.state状态内容又增加了两行;继续,而后开始第三次循环,如下;

可见,在MenuFacenameOnDrawItem函数中,程序对三个菜单进行了依次循环,diea.state状态也进行了依次展示;

下面开始研究正式的程序运行中菜单的diea.state状态

点“调试”-“开始执行(不调试)”

以上是鼠标刚刚点击Facename时,三个菜单所展示出来的diea.state状态。

然后,将鼠标移动到“Tiems New Roman”菜单上,保持悬浮不动,三个菜单中,只有“Tiems New Roman”菜单的diea.state状态发生了变化,其它两个菜单的状态没有发生变化,所以鼠标悬浮在第一个菜单上面时,窗口只展示了一项状态信息,如下:

再将鼠标移动到Arial菜单上面时,第一个菜单和第二个菜单的diea.state状态都发生了变化,第三个菜单依然没有变化,所以展示了两项信息,如下:

而后将鼠标移动到第三个菜单上,这时第一个菜单状态没有变化的,只有第二个和第三个菜单的状态发生了变化,所以程序展示如下:

 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------

2022.11.13更新代码如下;

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Drawing;
  6 using System.Windows.Forms;
  7 using System.Drawing.Text;
  8 
  9 namespace OwnerDrawMenu
 10 {
 11     class OwnerDrawMenu:Form
 12     {
 13         const int iFontPointSize = 18;  //用于菜单项目
 14         MenuItem miFacename;
 15 
 16         static void Main(string[] args)
 17         {
 18             Application.Run(new OwnerDrawMenu());
 19         }
 20         public OwnerDrawMenu()
 21         {
 22             Text = "Owner Draw Menu";
 23 
 24             //Top Level items
 25             Menu = new MainMenu();
 26             Menu.MenuItems.Add("&Facename");
 27 
 28             //子菜单项的内容
 29             string[] astrText = { "&Times New Roman","&Arial","&Courier New"};
 30             MenuItem[] ami = new MenuItem[astrText.Length];
 31 
 32             EventHandler ehOnClick = new EventHandler(MenuFacenameOnClick);
 33             MeasureItemEventHandler ehOnMeasureItem =
 34                 new MeasureItemEventHandler(MenuFacenameOnMeasureItem);
 35             DrawItemEventHandler ehOnDrawItem =
 36                 new DrawItemEventHandler(MenuFacenameOnDrawItem);
 37 
 38             for (int i = 0; i < ami.Length; i++)
 39             {
 40                 ami[i] = new MenuItem(astrText[i]);
 41                 ami[i].OwnerDraw = true;
 42                 ami[i].RadioCheck = true;
 43                 ami[i].Click += ehOnClick;
 44                 ami[i].MeasureItem += ehOnMeasureItem;
 45                 ami[i].DrawItem += ehOnDrawItem;
 46             }
 47             miFacename = ami[0];
 48             miFacename.Checked = true;
 49 
 50             Menu.MenuItems[0].MenuItems.AddRange(ami);
 51         }
 52 
 53         void MenuFacenameOnClick(object obj, EventArgs ea)
 54         {
 55             miFacename.Checked = false;
 56             miFacename = (MenuItem)obj;
 57             miFacename.Checked = true;
 58 
 59             Invalidate();
 60         }
 61 
 62         void MenuFacenameOnMeasureItem(object obj, MeasureItemEventArgs miea)
 63         {
 64             MenuItem mi = (MenuItem)obj;
 65             Font font = new Font(mi.Text.Substring(1),iFontPointSize);
 66 
 67             StringFormat strfmt = new StringFormat();
 68             strfmt.HotkeyPrefix = HotkeyPrefix.Show;
 69 
 70             SizeF sizef = miea.Graphics.MeasureString(mi.Text,font,1000,strfmt);
 71 
 72             miea.ItemWidth = (int)Math.Ceiling(sizef.Width);
 73             miea.ItemHeight = (int)Math.Ceiling(sizef.Height);
 74 
 75             miea.ItemWidth += SystemInformation.MenuCheckSize.Width * 
 76                                 miea.ItemHeight / 
 77                                     SystemInformation.MenuCheckSize.Height;
 78             miea.ItemWidth -= SystemInformation.MenuCheckSize.Width;
 79         }
 80 
 81         void MenuFacenameOnDrawItem(object obj, DrawItemEventArgs diea)
 82         {
 83             MenuItem mi = (MenuItem)obj;
 84             Graphics grfx = diea.Graphics;
 85             Brush brush;
 86 
 87             //创建字体和格式
 88             Font font = new Font(mi.Text.Substring(1),iFontPointSize);
 89             StringFormat strfmt = new StringFormat();
 90             strfmt.HotkeyPrefix = HotkeyPrefix.Show;
 91 
 92             //计算选择标记和文字矩形
 93             Rectangle rectCheck = diea.Bounds;
 94 
 95             rectCheck.Width = SystemInformation.MenuCheckSize.Width * rectCheck.Height / SystemInformation.MenuCheckSize.Height;
 96             Rectangle rectText = diea.Bounds;
 97             rectText.X += rectCheck.Width;
 98 
 99             //绘制
100             diea.DrawBackground();
101             if ((diea.State & DrawItemState.Checked) != 0)
102                  ControlPaint.DrawMenuGlyph(grfx,rectCheck,MenuGlyph.Arrow);   //此行代码为绘制菜单前的三角形“箭头”
103 
104             //测试diea.state
105             Console.WriteLine("对应的菜单 is {0}",obj.ToString());
106             Console.WriteLine("(diea.State & DrawItemState.Checked) is {0}", (diea.State & DrawItemState.Checked));
107             
108             if ((diea.State & DrawItemState.Checked) != 0)
109             
110                 brush = new SolidBrush(Color.Red);              //如果选中菜单的某一项内容,则此项内容的文字就变为红色;
111             else
112                 brush = new SolidBrush(Color.Yellow);           //未选中的其它菜单项内容,其文字就为黄色;
113 
114             grfx.DrawString(mi.Text,font,brush,rectText,strfmt);
115         }
116 
117         protected override void OnPaint(PaintEventArgs pea)
118         {
119             Graphics grfx = pea.Graphics;
120             Font font = new Font(miFacename.Text.Substring(1),12);
121             StringFormat strfmt = new StringFormat();
122             strfmt.Alignment = strfmt.LineAlignment = StringAlignment.Center;
123 
124             grfx.DrawString(Text,font,new SolidBrush(ForeColor),0,0);
125         }
126     }
127 }

此次代码更新了第105行代码,这样可读性更好

 

posted @ 2022-11-08 23:30  chenlight  阅读(87)  评论(0编辑  收藏  举报