菜单绘制项的状态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行代码,这样可读性更好