2015-05-22 125 views
4

的WinForms,我列出toolstripmenu项目如下:定位正确

ToolStripMenuItem of my program

我们可以看到快捷键列表是不正确缩进。

我已经搜索的解决方案,发现使用空间但我已经尝试过,它没有正常工作。

那么,是不是可以位置快捷键如下图所示,在所有菜单项的某个位置

ToolStripMenuItem of Visual Studio 2013

+0

另一种解决方案去应该是这样:设置'ShortcutKeys'财产,这样的'ShortcutKeyDisplayString'自动设置。将'ShowShortcutKeys'设置为true将正确显示项目旁边的快捷方式。 – Koryu

+0

我刚刚为你尝试过。这些项目右对齐。看起来你必须扩展课程并覆盖绘画。 :/ – Koryu

+0

@Koryu,对不起,我不知道改写这幅画。你能提供一些进一步的帮助吗? – Tops

回答

1

我搜索,阅读一些有关这个话题,但cound'nt找到工作的例子。所以我想我试着创建一个。这不是完美的,但开始的基础。例如,我没有尝试包含其他子项目的项目。

要呈现菜单项,您不必覆盖项目的'OnPaint方法。我们最好使用ToolStripProfessionalRenderer。渲染器将​​管理显示菜单项所需的所有内容。因此,我们必须创建我们自己的类MyToolStripProfessionalRenderer并设置Toolstrip.Renderer属性。

Public Class Form1 

    Public Sub New() 

    InitializeComponent() 
    MenuStrip1.Renderer = New MyToolStripProfessionalRenderer() 

    End Sub 
End Class 

在我们课程中,我们必须重写OnRenderItemText方法。此方法为项目名称和快捷方式绘制字符串。基本方法很简单,用右对齐绘制左对齐和快捷方式的名称。我们的自定义方法应该绘制左对齐的名称和左对齐的快捷方式。因此我们需要找出合适的地方来绘制捷径。我创建了一个检查所有项目快捷方式文本的循环来查找宽度最大的项目。从中创建一个矩形并在该矩形中绘制字符串。

注意:使用此示例时,您必须手动设置设计器中的ShortcutKeyDisplayString属性,因为它总是以其他方式始终为空。

/编辑各大:

我们也必须改变自动调整算法与每个dropdownmenu的设置。

新Autowidth:Imagewidth +一些空间+ 最大Itemtext +一些空间+大ShortcutText下+一些空间

enter image description here

所以我重写Initialize(toolStrip As System.Windows.Forms.ToolStrip)方法。 首先,我添加了一些常量来设置空格。要计算宽度,我抓取所有项目并查找子项目的最大文本,然后设置项目的新宽度。

注意:如果您的下拉菜单有另一个下拉菜单,那么您必须 添加递归。

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, 
           MenuItem.ContentRectangle.Top + 1, 
           ShortCutWidth, 
           MenuItem.Height) 
      ' drawing the shortcut 
      e.Graphics.DrawString(Shortcut, MenuItem.Font, New SolidBrush(MenuItem.ForeColor), 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 
+0

谢谢你的努力。我会尽力回复你。 – Tops

+0

你好@Koryu,我尝试过使用MenuStrip,但是我遇到了一些问题。问题:设计时间(text + shortcutdisplaystring)和运行时间(text + shorcutdisplaystring)在RunTime中都可见。设计文档和运行时文本都重叠。如果解决了,它会很棒。你可以编辑和帮助吗?谢谢。 – Tops

+0

@KnockKnock你可以发布设计器生成的代码为你的菜单?所以我可以将你的菜单复制到我的项目中。 – Koryu

0

下面是C#

private class MenuRenderer : ToolStripProfessionalRenderer { 

    Hashtable ht = new Hashtable(); 
    int shortcutTextMargin = 5; 
    Font cachedFont = null; 

    protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e) { 
     ToolStrip ts = e.Item.Owner; 
     if (ts.Font != cachedFont) { 
      cachedFont = ts.Font; // assumes all menu items use the same font 
      ht.Clear(); 
     } 

     var mi = e.Item as ToolStripMenuItem; 

     if (mi != null && mi.ShortcutKeys != (Keys) 0) { 
      if (e.Text != mi.Text) { // shortcut text 
       ToolStripMenuItem owner = (ToolStripMenuItem) e.Item.OwnerItem; 

       e.TextFormat = TextFormatFlags.VerticalCenter; 
       Size sz = TextRenderer.MeasureText(e.Graphics, e.Text, e.TextFont); 

       int w = owner.DropDown.Width; 
       int x = w - (sz.Width + shortcutTextMargin); 
       int? xShortcut = (int?) ht[owner]; 
       if (!xShortcut.HasValue || x < xShortcut.Value) { 
        xShortcut = x; 
        ht[owner] = xShortcut; 
        owner.DropDown.Invalidate(); 
       } 

       Rectangle r = e.TextRectangle; 
       r.X = xShortcut.Value; 
       e.TextRectangle = r; 
      } 
     } 

     base.OnRenderItemText(e); 
    } 
}