Vb.net ToolStripMenu项快捷键的正确定位
在WinForms中,我列出了toolstripmenu项,如下所示: 我们可以看到快捷键列表没有正确缩进 我已经搜索了解决方案并找到了使用空格的方法,但我已经尝试过了,但它没有正常工作 那么,是否可以将下图所示的快捷键放置在所有菜单项的特定位置Vb.net ToolStripMenu项快捷键的正确定位,vb.net,winforms,menustrip,Vb.net,Winforms,Menustrip,在WinForms中,我列出了toolstripmenu项,如下所示: 我们可以看到快捷键列表没有正确缩进 我已经搜索了解决方案并找到了使用空格的方法,但我已经尝试过了,但它没有正常工作 那么,是否可以将下图所示的快捷键放置在所有菜单项的特定位置 我搜索并阅读了一些关于这个主题的文章,但没有找到一个有效的例子。所以我想我试着创造一个。这并不完美,但却是一个开始的基础。例如,我没有尝试有附加子项的项目 要呈现菜单项,您不必覆盖项“OnPaint方法”。我们最好使用工具。渲染器将管理显示菜单项所需
我搜索并阅读了一些关于这个主题的文章,但没有找到一个有效的例子。所以我想我试着创造一个。这并不完美,但却是一个开始的基础。例如,我没有尝试有附加子项的项目 要呈现菜单项,您不必覆盖项“
OnPaint
方法”。我们最好使用工具
。渲染器将管理显示菜单项所需的一切。因此,我们必须创建自己的类MyToolStripProfessionalRenderer并设置Toolstrip.Renderer
属性
Public Class Form1
Public Sub New()
InitializeComponent()
MenuStrip1.Renderer = New MyToolStripProfessionalRenderer()
End Sub
End Class
在我们的类中,我们必须重写OnRenderItemText
方法。此方法为项目名称和快捷方式绘制字符串。基本方法很简单,使用左对齐绘制名称,使用右对齐绘制快捷方式。我们的自定义方法应该使用左对齐绘制名称,使用左对齐绘制快捷方式。因此,我们需要找到合适的地方画捷径。我创建了一个循环,检查所有项目的快捷方式文本,以找到宽度最大的项目。从中创建一个矩形,并在此矩形中绘制字符串
注意:使用此示例时,必须在设计器中手动设置ShortcutKeyDisplayString
属性,否则它总是空的
/major编辑:
我们还必须更改autosize算法以设置每个下拉菜单的with
新的自动宽度:Imagewidth+一些空间+
最大项文本+一些空格+最大快捷键文本+一些空格
因此,我重写了初始化(toolStrip作为System.Windows.Forms.toolStrip)
方法。
首先,我添加了一些常量来设置空格。要计算宽度,我将遍历所有项目,找到子项目中最大的文本,然后为这些项目设置新的宽度
注意:如果你的下拉菜单有另一个下拉菜单,那么你必须
添加递归
在
C#
私有类菜单渲染器:ToolStripProfessionalRenderer{
Hashtable ht=新的Hashtable();
int shortcutTextMargin=5;
字体cachedFont=null;
受保护的覆盖无效OnRenderItemText(ToolStripItemTextRenderReventArgs e){
工具条ts=e.Item.Owner;
如果(ts.Font!=cachedFont){
cachedFont=ts.Font;//假设所有菜单项使用相同的字体
ht.Clear();
}
var mi=e.作为ToolStripMenuItem的项目;
if(mi!=null&&mi.ShortcutKeys!=(Keys)0){
如果(e.Text!=mi.Text){//快捷方式文本
ToolStripMenuItem所有者=(ToolStripMenuItem)e.Item.OwnerItem;
e、 TextFormat=TextFormatFlags.VerticalCenter;
Size sz=TextRenderer.MeasureText(如图形、文字、字体);
int w=owner.DropDown.Width;
int x=w-(sz.Width+shortcutTextMargin);
int?xShortcut=(int?)ht[所有者];
如果(!xShortcut.HasValue | | x
方法应该是:设置ShortcutKeys
属性,这样可以自动设置ShortcutKeyDisplayString
。将ShowShortcutKeys
设置为true应该可以正确显示项目旁边的快捷方式。我刚刚为您尝试过。项目有右对齐,然后。看起来您必须扩展类并覆盖绘画:/@Koryu,对不起,我不知道怎么改写这幅画。你能提供进一步的帮助吗?对不起,没那么容易。如果我是你的话,我会选择ShowShortcutKeys属性并使用右对齐,这样的一点好处太多了。或者,如果你想要一个真正别致的菜单,请查看一些功能区工具栏。如果你想使用工具StripMenuItem
也许其他任何人都可以帮助你。有一个很好的理由它可以这样工作,一定要小心。你无法与VS菜单相比,微软花了很多钱来本地化他们的应用程序。很难匹配,你不会喜欢发现绳子被剪断,比如说,臭名昭著的冗长的德语。谢谢你的努力。我会试试看然后再给你回复。你好@Koryu,我试过使用MenuStrip,但我遇到了一个小问题。问题:设计时(text+shortcutdisplaystring)和运行时(text+shorcutdisplaystring)在运行时都可见。设计和运行时文本都是重叠的。如果解决了,它将非常有效。你能编辑和帮助吗?谢谢。@KnockKnock你能为你的菜单发布设计器生成的代码吗?所以我可以将你的菜单复制到我的项目中。我使用了一个自定义的自动调整算法来避免重叠。删除了C#代码,任何人请修复语法突出显示:)您非常有帮助,非常感谢。它起作用了。我们不能保持联系吗?因为你似乎很有帮助,我也需要一位导师:)。
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
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);
}
}