在的WinForms,我列出toolstripmenu項目如下:定位正確
我們可以看到快捷鍵列表是不正確縮進。
我已經搜索的解決方案,發現使用空間但我已經嘗試過,它沒有正常工作。
那麼,是不是可以位置的快捷鍵如下圖所示,在所有菜單項的某個位置?
在的WinForms,我列出toolstripmenu項目如下:定位正確
我們可以看到快捷鍵列表是不正確縮進。
我已經搜索的解決方案,發現使用空間但我已經嘗試過,它沒有正常工作。
那麼,是不是可以位置的快捷鍵如下圖所示,在所有菜單項的某個位置?
我搜索,閱讀一些有關這個話題,但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下+一些空間
所以我重寫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
下面是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);
}
}
另一種解決方案去應該是這樣:設置'ShortcutKeys'財產,這樣的'ShortcutKeyDisplayString'自動設置。將'ShowShortcutKeys'設置爲true將正確顯示項目旁邊的快捷方式。 – Koryu
我剛剛爲你嘗試過。這些項目右對齊。看起來你必須擴展課程並覆蓋繪畫。 :/ – Koryu
@Koryu,對不起,我不知道改寫這幅畫。你能提供一些進一步的幫助嗎? – Tops