在 ContextMenuStrip 中更改图像和文本之间的 space

Change space between Image and Text in ContextMenuStrip

在我的应用程序中,我有一个包含两个项目的 ContextMenuStrip。 每个项目都有一个图像和一个文本。菜单项的图像部分与其文本之间存在默认间隙,如下图所示(间隙由红色箭头指示)。

我想通过向左移动文本来减少水平间隙,使间隙减少到最大 1 个像素。

可能吗?如果可以我怎么办?

展示如何处理通用 ToolStripProfessionalRenderer and a connected ProfessionalColorTable 的示例设置,用于个性化 ToolStrip(MenuStrip、ContextMenuStrip 等)的呈现和呈现。

它被组织在具有不同职责的不同对象中:

▶ 一个 Handler class(此处命名为 MenuDesigner)负责初始化其他对象(Renderer、ColorTable 和颜色定义)。
它还公开了 public 允许自定义呈现和 MenuItems 外观的属性和方法。
这是唯一允许消费者与之交互的对象。

▶ 派生自ToolStripProfessionalRenderer的class对象(此处命名为MenuDesignerRenderer),负责菜单项的渲染,覆盖(部分或完全)默认行为。在此示例中(与问题相关),它覆盖 OnRenderItemText - to customize the position of the MenuItems Text based on the value of the TextOffset custom property and in relation to the ToolStrip padding - and OnRenderSeparator,绘制 Separator 项目(如果有)以调整到项目文本的新位置。
使用 MenuDesigner 处理程序的 TextOffset 属性.

设置文本偏移量

▶ 一个class对象派生ProfessionalColorTable(这里,命名为MenuColorTable),用于覆盖颜色 Table 的部分或全部默认属性,这些属性定义 ToolStrip/MenuStrip 的标准颜色,以分配自定义颜色。

▶ 一个密封的(在VB.Net中设置为NotInheritable)class(这里命名为MenuRendererColors)带静态(Shared) 属性,存储自定义颜色定义,然后将其分配给 ProfessionalColorTable.
描述的不同对象和部分 其中一些颜色可以使用 MenuDesigner 处理程序重新定义。
在示例代码中,TextColor(项目文本的颜色)和SelectionColor(选择时项目的颜色)


MenuDesigner 已初始化,在其构造函数中指定要自定义的 ToolStrip - 在本例中为 ContextMenuStrip。 MenuDesigner handler 的初始化也初始化了 Renderer 和 ColorTable.
→ 当然,可以使用任何其他 ProfessonalColorTable 派生的 class 来代替这里介绍的
→ 这同样适用于定义自定义颜色的 class。

● 在Form Designer中建立一个ContextMenuStrip(这里命名为MyContextMenuStrip),添加一个引用MenuDesigner的私有字段并在表单构造函数,传递ContextMenuStrip自定义:

Public Class SomeForm
    Private toolStripDesigner As MenuDesigner = Nothing

    Public Sub New()
        InitializeComponent()
        toolStripDesigner = New MenuDesigner(MyContextMenuStrip)
    End Sub

   ' [...]
End Class

要更改菜单项文本的位置,请将新值设置为 MenuDesigner.TextOffset 属性:

' Move the MenuItems Text 8 pixels to the left
toolStripDesigner.TextOffset = -8

TextOffset属性将偏移量限制在(-8, 30)范围内:8像素是Text的默认padding,在[=59=中是hard-coded ], 作为 DropDownMenus 的其他部分。
这些值会在必要时缩放。

要更改所选项目的文本颜色和背景颜色,请设置 MenuDesigner class:

公开的相应属性
' Changes the Color of Text of the MenuItems
toolStripDesigner.TextColor = Color.LightGreen

' Changes the Background Color of a selected MenuItems 
toolStripDesigner.SelectionColor = Color.MidnightBlue

可以向 MenuDesigner 处理程序添加更多属性或方法,以更改自定义颜色或在 run-time 处创建自定义行为。


这是它的工作原理:


菜单设计器class:
这是处理程序 class,用于初始化 ToolStripProfessionalRenderer 和相关的 ProfessionalColorTable
此对象可以公开 public 属性 和消费者可以 set/call 修改 ColorTable 设置和 Renderer 行为的方法。

它应该是唯一负责并允许与其他对象交互的对象(它充当代理 -> 这里所有 class 都是 public - 它更容易测试 - 但都应该是 internal (Friend) 或 private,具体取决于用例。

Imports System.Drawing
Imports System.Windows.Forms

Public Class MenuDesigner
    Private m_TextOffset As Integer = 0

    Public Sub New(toolStrip As ToolStrip)
        Renderer = New MenuDesignerRenderer()
        If toolStrip IsNot Nothing Then
            Initialize(toolStrip)
        End If
    End Sub

    Public Sub Initialize(toolStrip As ToolStrip)
        toolStrip.Renderer = Renderer
    End Sub

    Public ReadOnly Property Renderer As MenuDesignerRenderer

    Public Property TextColor As Color
        Get
            Return MenuRendererColors.Text
        End Get
        Set
            MenuRendererColors.Text = Value
        End Set
    End Property

    Public Property SelectionColor As Color
        Get
            Return MenuRendererColors.Selection
        End Get
        Set
            MenuRendererColors.Selection = Value
        End Set
    End Property

    Public Property TextOffset As Integer
        Get
            Return m_TextOffset
        End Get
        Set
            If Value <> m_TextOffset Then
                m_TextOffset = Math.Min(Math.Max(-8, Value), 30)
                Renderer.TextOffset = m_TextOffset
            End If
        End Set
    End Property
End Class

渲染器class (ToolStripProfessionalRenderer):

这些值和位置,e.ToolStrip.Padding.Left - 2, 3, e.Item.Width, 3,不是幻数,这些是hard-coded值(正如之前链接的 .Net 源代码中所示)由这些 classes 的设计者设置:2 像素是添加到默认填充的值,3 是偏移量高度为 6 像素的框内的分隔线。

Imports System.Drawing
Imports System.Windows.Forms

Public Class MenuDesignerRenderer
    Inherits ToolStripProfessionalRenderer

    Private m_colorTable As ProfessionalColorTable = Nothing

    Public Sub New()
        Me.New(New MenuColorTable())
    End Sub

    Public Sub New(colorTable As ProfessionalColorTable)
        MyBase.New(colorTable)
        m_colorTable = colorTable
    End Sub

    Friend Property TextOffset As Integer = 0

    Protected Overrides Sub OnRenderItemBackground(e As ToolStripItemRenderEventArgs)
        MyBase.OnRenderItemBackground(e)
        ' Customize when needed
    End Sub

    Protected Overrides Sub OnRenderSeparator(e As ToolStripSeparatorRenderEventArgs)
        MyBase.OnRenderSeparator(e)
        Using penForeground As New Pen(m_colorTable.SeparatorDark, 1),
            penBackground As New Pen(e.Item.BackColor, 1)
            e.Graphics.DrawLine(penBackground, e.ToolStrip.Padding.Left - 2, 3, e.Item.Width, 3)
            e.Graphics.DrawLine(penForeground, e.ToolStrip.Padding.Left + TextOffset, 3, e.Item.Width, 3)
        End Using
    End Sub

    Protected Overrides Sub OnRenderItemText(e As ToolStripItemTextRenderEventArgs)
        e.Item.ForeColor = MenuRendererColors.Text
        Dim textRect = e.TextRectangle
        textRect.Offset(TextOffset, 0)
        e.TextRectangle = textRect
        MyBase.OnRenderItemText(e)
    End Sub
End Class

色彩Tableclass(专业色彩Table):
class 覆盖了将颜色分配给 MenuItems 部件的属性,以设置我们 MenuRendererColors class.

中定义的自定义颜色
Imports System.Drawing
Imports System.Windows.Forms

Public Class MenuColorTable
    Inherits ProfessionalColorTable

    Public Overrides ReadOnly Property ToolStripBorder As Color = MenuRendererColors.Background
    Public Overrides ReadOnly Property ToolStripGradientBegin As Color = MenuRendererColors.Background
    Public Overrides ReadOnly Property ToolStripGradientEnd As Color = MenuRendererColors.Background
    Public Overrides ReadOnly Property ToolStripDropDownBackground As Color = MenuRendererColors.Background

    Public Overrides ReadOnly Property MenuBorder As Color = MenuRendererColors.Background
    Public Overrides ReadOnly Property MenuItemBorder As Color = MenuRendererColors.ImageBand
    Public Overrides ReadOnly Property MenuStripGradientBegin As Color = MenuRendererColors.Background
    Public Overrides ReadOnly Property MenuStripGradientEnd As Color = MenuRendererColors.Background

    Public Overrides ReadOnly Property CheckBackground As Color = MenuRendererColors.Background
    Public Overrides ReadOnly Property CheckPressedBackground As Color = MenuRendererColors.Background
    Public Overrides ReadOnly Property CheckSelectedBackground As Color = MenuRendererColors.Background

    Public Overrides ReadOnly Property MenuItemSelected As Color = MenuRendererColors.Selection
    Public Overrides ReadOnly Property MenuItemSelectedGradientBegin As Color = MenuRendererColors.Selection
    Public Overrides ReadOnly Property MenuItemSelectedGradientEnd As Color = MenuRendererColors.Selection
    Public Overrides ReadOnly Property MenuItemPressedGradientBegin As Color = MenuRendererColors.Selection
    Public Overrides ReadOnly Property MenuItemPressedGradientEnd As Color = MenuRendererColors.Selection

    Public Overrides ReadOnly Property SeparatorDark As Color = MenuRendererColors.SeparatorDark
    Public Overrides ReadOnly Property SeparatorLight As Color = MenuRendererColors.SeparatorLight

    Public Overrides ReadOnly Property ImageMarginGradientBegin As Color = MenuRendererColors.ImageBand
    Public Overrides ReadOnly Property ImageMarginGradientMiddle As Color = MenuRendererColors.ImageBand
    Public Overrides ReadOnly Property ImageMarginGradientEnd As Color = MenuRendererColors.ImageBand
    Public Overrides ReadOnly Property ImageMarginRevealedGradientBegin As Color = MenuRendererColors.ImageBand
    Public Overrides ReadOnly Property ImageMarginRevealedGradientMiddle As Color = MenuRendererColors.ImageBand
    Public Overrides ReadOnly Property ImageMarginRevealedGradientEnd As Color = MenuRendererColors.ImageBand
End Class

颜色定义class:

存储用于自定义 MenusItems 外观的颜色。如果需要,可以使用 manager class、MenuDesigner.

更改这些设置
Imports System.Drawing

Public NotInheritable Class MenuRendererColors
    Public Shared Property Text As Color = Color.White
    Public Shared Property Background As Color = Color.FromArgb(32, 32, 32)
    Public Shared Property Selection As Color = Color.FromArgb(200, Color.DodgerBlue)
    Public Shared Property ImageBand As Color = Color.FromArgb(200, 200, 200)
    Public Shared Property CheckBoxBand As Color = Color.FromArgb(200, 200, 200)
    Public Shared Property SeparatorDark As Color = Color.DodgerBlue
    Public Shared Property SeparatorLight As Color = Color.LawnGreen
End Class