Reputation: 173
I have found this Custom Control, derived from GroupBox, that allows to change the color of its border.
I understand that the code originally came from StackOverflow, although I cannot find it.
For some reason, when setting the Text Property of the GroupBox, the last letter is always cut out.
Can anyone with more experience than me see anything in the code which is causing this?
Public Class myGroupBox
Inherits GroupBox
Private borderColor As Color
Public Sub New()
MyBase.New
Me.borderColor = Color.Blue
End Sub
Public Property BorderColour() As Color
Get
Return Me.borderColor
End Get
Set(ByVal value As Color)
Me.borderColor = value
End Set
End Property
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
Dim tSize As Size = TextRenderer.MeasureText(Me.Text, Me.Font)
Dim borderRect As Rectangle = e.ClipRectangle
borderRect.Y = (borderRect.Y + (tSize.Height / 2))
borderRect.Height = (borderRect.Height - (tSize.Height / 2))
ControlPaint.DrawBorder(e.Graphics, borderRect, Me.borderColor, ButtonBorderStyle.Solid)
Dim textRect As Rectangle = e.ClipRectangle
textRect.X = (textRect.X + 6)
textRect.Width = tSize.Width
textRect.Height = tSize.Height
e.Graphics.FillRectangle(New SolidBrush(Me.BackColor), textRect)
e.Graphics.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), textRect)
End Sub
End Class
Upvotes: 1
Views: 818
Reputation: 1
I tried Jimi's code and successfully run it. However, when the said groupbox Text is empty, it will have a small gap (the border is not totally closed). I'm no expert with VB.Net, and find it difficult to test the code.
Fortunately, using the original code as posted by Ian Barber, with trial and errors it was solved by adding a constant value to the text size width (textRect.Width = tSize.Width + 2).
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
Dim tSize As SizeF = e.Graphics.MeasureString(Me.Text, Me.Font) 'TextRenderer.MeasureText(Me.Text, Me.Font)
Dim borderRect As Rectangle = e.ClipRectangle
borderRect.Y = (borderRect.Y + (tSize.Height / 2))
borderRect.Height = (borderRect.Height - (tSize.Height / 2))
ControlPaint.DrawBorder(e.Graphics, borderRect, Me.borderColor, ButtonBorderStyle.Solid)
Dim textRect As Rectangle = e.ClipRectangle
textRect.X = textRect.X + 6
textRect.Width = tSize.Width + 2
textRect.Height = tSize.Height
e.Graphics.FillRectangle(New SolidBrush(Me.BackColor), textRect)
e.Graphics.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), textRect)
End Sub
Upvotes: 0
Reputation: 32223
There are some problems with that code:
TextRenderer.MeasureText
, but the current Graphics (IdeviceContext
) object is not passed to method.e.ClipRectangle
as the measure of the Border: better use Control.ClientRectangle
Graphics.DrawString
is used to draw the Text, when another tool was used to measure itOption Strict Off
► To note: this is not how the Framework draws the borders of a GroupBox. We should draw lines instead, otherwise the text cannot be rendered transparent: since it's the drawn text that hides the line drawn by ControlPaint.DrawBorder
, the text background cannot be transparent.
Here's a revisited version of that Control, with some adjustments that may be useful in other occasions:
If you think that the Text is drawn too close to the left side, just offset it as required. You could also add a Property to defined the alignment.
SystemColors.Window
: use the PropertyGrid to set another Color.Public Class myGroupBox
Inherits GroupBox
Private ReadOnly flags As TextFormatFlags =
TextFormatFlags.Top Or TextFormatFlags.Left Or
TextFormatFlags.LeftAndRightPadding Or TextFormatFlags.EndEllipsis
Private m_BorderColor As Color = SystemColors.Window
Public Property BorderColor As Color
Get
Return m_BorderColor
End Get
Set
m_BorderColor = Value
Me.Invalidate()
If DesignMode Then Me.Parent?.Invalidate(Me.Bounds)
End Set
End Property
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
Dim midText = TextRenderer.MeasureText(e.Graphics, Text, Font, ClientSize).Height \ 2 + 2
Dim rect = New Rectangle(0, midText, ClientSize.Width, ClientSize.Height - midText)
ControlPaint.DrawBorder(e.Graphics, rect, BorderColor, ButtonBorderStyle.Solid)
Dim textRect = Rectangle.Inflate(ClientRectangle, -4, 0)
TextRenderer.DrawText(e.Graphics, $" {Me.Text} ", Font, textRect, ForeColor, BackColor, flags)
End Sub
End Class
Upvotes: 2
Reputation: 146
Do not mix TextRenderer
methods and Graphics
methods for string measurement and drawing. When you have a graphics object, you should use it.
Use Graphics.MeasureString()
and Graphics.DrawString()
or TextRenderer.MeasureText()
and TextRenderer.DrawText()
.
Upvotes: 2