Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
999 views
in Technique[技术] by (71.8m points)

vb.net - Change space between Image and Text in ContextMenuStrip

In my application, I have a ContextMenuStrip with two items. Each item has an image and a text. There's a default gap between the Image section of the Menu Items and their text, as shown in the image below (the gap is indicated by red arrows).

enter image description here

I want to reduce the horizontal gap by moving the text towards the left, so that the gap is reduced to a maximum of 1 pixel.

Is it possible? If yes how can I?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

A sample setup that shows how to handle a generic ToolStripProfessionalRenderer and a connected ProfessionalColorTable, used to personalize the rendering and presentation of ToolStrips (MenuStrip, ContextMenuStrip etc.).

It's organized in different objects with different responsibilities:

? A Handler class (here, named MenuDesigner) which is responsible for the initialization of the other objects (Renderer, ColorTable and Color definitions).
It also exposes public properties and methods that allow to customize the rendering and the aspect of the MenuItems.
It's the only object that consumers should be allowed to interact with.

? A class object derived from ToolStripProfessionalRenderer (here, named MenuDesignerRenderer), responsible for the rendering of the Menu Items, overriding (partially or completely) the default behavior. In this example (in relation to the question), it overrides 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, which draws the Separator Items, if any, to adjust to the new position of the Items Text.
The Text offset is set using the MenuDesigner handler's TextOffset Property.

? A class object derived ProfessionalColorTable (here, named MenuColorTable), which is used to override some or all the default Properties of the Color Table which define the standard Colors of a ToolStrip/MenuStrip, to assign custom colors.

? A sealed (set to NotInheritable in VB.Net) class (here, named MenuRendererColors) with static (Shared) properties, stores the custom Color definitions, which are then assigned to the different objects and parts described by the ProfessionalColorTable.
Some of these Colors can be redefined using the MenuDesigner handler.
In the sample code, TextColor (Color of the Items Text) and SelectionColor (Color of the Items when selected)


● The MenuDesigner is initialized specifying, in its Constructor, the ToolStrip to customize - a ContextMenuStrip in this case. The initialization of the MenuDesigner handler also initializes the Renderer and the ColorTable.
→ Of course, any other ProfessonalColorTable derived class can be used instead of the one presented here.
→ The same applies to the class that defines the custom Colors.

● Build a ContextMenuStrip (here named MyContextMenuStrip) in the Form Designer, add a private field that references the MenuDesigner and initialize it in the Form constructor, passing the ContextMenuStrip to customize:

Public Class SomeForm
    Private toolStripDesigner As MenuDesigner = Nothing

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

   ' [...]
End Class

To change the position on the MenuItems Text, set a new value to the MenuDesigner.TextOffset Property:

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

The TextOffset property limits the offset to the range (-8, 30): 8 pixels is the default padding of the Text, it's hard-coded in the ToolStripDropDownMenu class, as other parts of the DropDownMenus.
These values are scaled when necessary.

To change the Color of Text and the Background Color of a selected Item, set the corresponding properties exposed by the 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

More properties or methods can be added to the MenuDesigner handler to change custom Colors or create custom behaviors at run-time.


This is how it works:

Custom ToolStripProfessionalRenderer - ProfessionalColorTable


MenuDesigner class:
this is the handler class, used to initialize a ToolStripProfessionalRenderer and the related ProfessionalColorTable.
This object can expose public property and methods that a consumer can set/call to modify settings of the ColorTable and the behavior of the Renderer.

It should be the only object responsible and allowed to interact with the other (it acts as a proxy -> here all classes are public - it's easier to test - but all should be internal (Friend) or private, depending on the use case).

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

Renderer class (ToolStripProfessionalRenderer):

These values and positions, e.ToolStrip.Padding.Left - 2, 3, e.Item.Width, 3, are not magic numbers, these are hard-coded values (as it can be seen in the .Net source code linked before) set by the designers of these classes: 2 pixels is a value added to the default padding, 3 is the offset of the Separator line inside its box of 6 pixels in height.

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

Color Table class (ProfessionalColorTable):
This class overrides the properties that assign Colors to MenuItems parts to set the custom color defined in our 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 ImageMarginRevealedGradientB

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...