vb.net – 正确定位ToolStripMenu项的快捷键

在WinForms中,我列出了toolstripmenu项目,如下所示:

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

相关文章

Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强...
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办...
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace...
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用...
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选...
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As Dat...