2015-05-22 168 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); 
    } 
}