We can see that the list of shortcut key is not properly indented.
I have searched for the solution and found to use spaces but I have tried that and it didn’t work properly.
那么,是否可以将快捷键如下图所示放置在所有菜单项的特定位置?
解决方法
要渲染菜单项,您不必重写Items的OnPaint方法.我们最好使用ToolStripProfessionalRenderer.渲染器将管理显示菜单项所需的所有内容.因此,我们必须创建自己的类MyToolStripProfessionalRenderer并设置Toolstrip.Renderer属性.
Public Class Form1 Public Sub New() InitializeComponent() MenuStrip1.Renderer = New MyToolStripProfessionalRenderer() End Sub End Class
在我们的类中,我们必须覆盖OnRenderItemText方法.此方法为项目名称和快捷方式绘制字符串.基本方法很简单,使用左对齐绘制名称,使用右对齐绘制快捷方式.我们的自定义方法应该使用左对齐绘制名称,使用左对齐绘制快捷方式.因此,我们需要找出绘制快捷方式的适当位置.我创建了一个循环检查所有项目的快捷方式文本,以找到具有最高宽度的项目.从中创建一个矩形并在此矩形中绘制字符串.
注意:使用此示例时,您必须手动设置设计器中的ShortcutKeyDisplayString属性,否则它始终为null.
/主要编辑:
New Autowidth: Imagewidth + some space +
largest Itemtext + some space + largest ShortCutText + some space
因此,我重写Initialize(toolStrip As System.Windows.Forms.ToolStrip)方法.
首先,我添加了一些常量来设置空格.要计算宽度,我将浏览所有项目并找到子项目的最大文本,然后设置项目的新宽度.
Note: If your dropdownmenu has another dropdownmenu then you have to
add recursion.
Imports System.Windows.Forms Public Class MyToolStripProfessionalRenderer Inherits ToolStripProfessionalRenderer Protected iconwidth As Integer = 22 ' the width of image icons Protected paddingIconToText As Integer = 3 Protected paddingTextToShortCut As Integer = 20 Protected paddingShortCutToBoarder As Integer = 20 Private Enum TextType Text = 0 Shortcut = 1 End Enum Protected Overrides Sub OnRenderItemText(e As System.Windows.Forms.ToolStripItemTextRenderEventArgs) ' render only ToolStripMenuItems If e.Item.IsOnDropDown And TypeOf e.Item Is ToolStripMenuItem Then Dim MenuItem As ToolStripMenuItem = e.Item Dim Name As String = MenuItem.Text Dim Shortcut As String = MenuItem.ShortcutKeyDisplayString 'avoid double draw. The method is called twice for each item,check what should be drawn,Text or Shortcut? Dim Mode As TextType If e.Text = Name Then Mode = TextType.Text Else Mode = TextType.Shortcut End If If Mode = TextType.Text Then ' this is our column for the menuitem text Dim FirstColumn As Rectangle = New Rectangle(MenuItem.ContentRectangle.Left + iconwidth + paddingIconToText,MenuItem.ContentRectangle.Top + 1,MenuItem.Width - iconwidth - paddingIconToText,MenuItem.Height) ' drawing the menu item e.Graphics.DrawString(Name,MenuItem.Font,New SolidBrush(MenuItem.ForeColor),FirstColumn) ' this is the Shortcut to display,be sure to have set it manually Else ' to align the text on the wanted position,we need to know the width for the shortcuts,this depends also on the other menu items Dim CurStrip As ToolStrip = MenuItem.GetCurrentParent() Dim fShortCutWidth As Single = 0 ' lets find the other menuitems for this group For Each item As Object In CurStrip.Items ' lets look for the ToolStripMenuItem only If TypeOf item Is ToolStripMenuItem Then Dim ChildItem As ToolStripMenuItem = item Dim sCurShortcut As String = ChildItem.ShortcutKeyDisplayString ' how many pixels are needed to draw the current shortcut? Dim size As SizeF = e.Graphics.MeasureString(sCurShortcut,ChildItem.Font) If size.Width > fShortCutWidth Then fShortCutWidth = size.Width ' save it for later End If End If Next ' avoid to lose 1 pixel by casting to integer Dim ShortCutWidth As Integer = Convert.ToInt32(fShortCutWidth) + 1 If fShortCutWidth > 0 Then ' this is our second column for the shortcut text Dim SecondColumn As Rectangle = New Rectangle(MenuItem.Width - ShortCutWidth - paddingShortCutToBoarder,ShortCutWidth,MenuItem.Height) ' drawing the shortcut e.Graphics.DrawString(Shortcut,SecondColumn) End If End If Else ' there might be other items,use the default method MyBase.OnRenderItemText(e) End If End Sub Protected Overrides Sub Initialize(toolStrip As System.Windows.Forms.ToolStrip) MyBase.Initialize(toolStrip) ' custom autosize algorithm ' 1: Find all dropdownbuttons ' 2: Get all Menuitems within dropdown ' 3: find the largest string of the dropdownitems text ' 4: find the latgest string of the dropdownitems shortcuttext ' 5: set the width for all items = picture width + padding + longest_itemtext + padding + longest_shortcuttext + padding For Each item As ToolStripItem In toolStrip.Items ' get all dropdownbuttons If TypeOf item Is ToolStripDropDownButton Then Dim btn As ToolStripDropDownButton = item If btn.HasDropDownItems Then ' dropdownitems Dim MaxSizeOfItemName As Single = 0 Dim MaxSizeOfShortCutName As Single = 0 Dim CurSizeOfItemName As Single = 0 Dim CurSizeOfShortCutName As Single = 0 For Each child As ToolStripItem In btn.DropDownItems ' menu items within dropdown menu ' find the largest strings of dropdownitems If TypeOf child Is ToolStripMenuItem Then Dim CurrentMenuItem As ToolStripMenuItem = child CurSizeOfItemName = TextRenderer.MeasureText(CurrentMenuItem.Text,child.Font).Width CurSizeOfShortCutName = TextRenderer.MeasureText(CurrentMenuItem.ShortcutKeyDisplayString,child.Font).Width MaxSizeOfItemName = Math.Max(MaxSizeOfItemName,CurSizeOfItemName) MaxSizeOfShortCutName = Math.Max(MaxSizeOfShortCutName,CurSizeOfShortCutName) End If Next If MaxSizeOfItemName > 0 Then Dim autowidth As Integer = iconwidth + paddingIconToText + Convert.ToInt32(MaxSizeOfItemName) + 1 + paddingTextToShortCut + Convert.ToInt32(MaxSizeOfShortCutName) + 1 + paddingShortCutToBoarder ' it's not enough to set only the dropdownitems' width,also have to change the ToolStripDropDownMenu width Dim menu As ToolStripDropDownMenu = btn.DropDownItems.Item(0).GetCurrentParent() ' maybe there is a better way to get the menuobject?! menu.AutoSize = False menu.Width = autowidth For Each child As ToolStripItem In btn.DropDownItems child.AutoSize = False child.Width = autowidth Next End If ' MaxSizeOfItemName ' CAUTION: this works only for the first level of menuitems,if your dropdownmenu has another dropdownmenu,move the code above into a method and add recursion for each dropdownbutton with subitems End If ' btn.HasDropDownItems End If ' TypeOf item Is ToolStripDropDownButton Next 'For Each item As ToolStripItem End Sub End Class