SCENARIO
在 WinForms 中,我对GroupBox
进行了细分,以更改此控件的边框颜色。
问题
在设计模式(在VisualStudio的可视化构建器中),如果我对Groupbox
内的控件执行任何类型的更改,请点击每个控件都要更改textfont,然后我的Groupbox
重新绘制控件,如下所示:
注意:在使控件无效后,它会再次正确重绘。
问题
当所有者绘制存储像GroupBox
这样的控件集合的容器时,这是一个已知问题?
我在OnPaint
方法中缺少修复此绘画问题的方法吗?
CODE
VB版:
''' <summary>
''' Handles the <see cref="E:Paint"/> event.
''' </summary>
''' <param name="e">A <see cref="T:PaintEventArgs"/> that contains the event data.</param>
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
' MyBase.OnPaint(e)
Me.DrawBorder(e)
End Sub
''' <summary>
''' Draws a border on the control surface.
''' </summary>
Private Sub DrawBorder(ByVal e As PaintEventArgs)
' The groupbox header text size.
Dim textSize As Size = TextRenderer.MeasureText(Me.Text, Me.Font)
' The width of the blankspace drawn at the right side of the text.
Dim blankWidthSpace As Integer = 3
' The thex horizontal offset.
Dim textOffset As Integer = 7
' The rectangle where to draw the border.
Dim borderRect As Rectangle = e.ClipRectangle
With borderRect
.Y = .Y + (textSize.Height \ 2)
.Height = .Height - (textSize.Height \ 2)
End With
' The rectangle where to draw the header text.
Dim textRect As Rectangle = e.ClipRectangle
With textRect
.X = .X + textOffset
.Width = (textSize.Width - blankWidthSpace)
.Height = textSize.Height
End With
' Draw the border.
ControlPaint.DrawBorder(e.Graphics, borderRect, Me.borderColor1, Me.borderStyle1)
' Fill the text rectangle.
e.Graphics.FillRectangle(New SolidBrush(Me.BackColor), textRect)
' Draw the text on the text rectangle.
textRect.Width = textSize.Width + (blankWidthSpace * 2) ' Fix the right side space.
e.Graphics.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), textRect)
End Sub
C#版本:
/// <summary>
/// Handles the <see cref="E:Paint"/> event.
/// </summary>
/// <param name="e">A <see cref="T:PaintEventArgs"/> that contains the event data.</param>
protected override void OnPaint(PaintEventArgs e)
{
// MyBase.OnPaint(e)
this.DrawBorder(e);
/// <summary>
/// Draws a border on the control surface.
/// </summary>
private void DrawBorder(PaintEventArgs e)
{
// The groupbox header text size.
Size textSize = TextRenderer.MeasureText(this.Text, this.Font);
// The width of the blankspace drawn at the right side of the text.
int blankWidthSpace = 3;
// The thex horizontal offset.
int textOffset = 7;
// The rectangle where to draw the border.
Rectangle borderRect = e.ClipRectangle;
var _with1 = borderRect;
_with1.Y = _with1.Y + (textSize.Height / 2);
_with1.Height = _with1.Height - (textSize.Height / 2);
// The rectangle where to draw the header text.
Rectangle textRect = e.ClipRectangle;
var _with2 = textRect;
_with2.X = _with2.X + textOffset;
_with2.Width = (textSize.Width - blankWidthSpace);
_with2.Height = textSize.Height;
// Draw the border.
ControlPaint.DrawBorder(e.Graphics, borderRect, this.borderColor1, this.borderStyle1);
// Fill the text rectangle.
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), textRect);
// Draw the text on the text rectangle.
textRect.Width = textSize.Width + (blankWidthSpace * 2);
// Fix the right side space.
e.Graphics.DrawString(this.Text, this.Font, new SolidBrush(this.ForeColor), textRect);
}
//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================
答案 0 :(得分:1)
您的代码和方法实际上有几个问题:
' The rectangle where to draw the border.
Dim borderRect As Rectangle = e.ClipRectangle
' and:
' The rectangle where to draw the header text.
Dim textRect As Rectangle = e.ClipRectangle
如果您选择一个子控件并稍微移动它,您将遇到图像显示的问题。原因是Windows不会要求控件重新绘制整个自我以进行如此小的更改。相反,它会使子控件周围的小区域无效,并将其作为ClipRectangle
传递。在某些情况下,它实际上是不正确的。
因此,基于GroupBox
定位e.ClipRectangle
边框Rect将绘制边框的一部分,并且刚刚移动的控件周围区域的标题。使用Bounds
调整各种事项
那应该摆脱上面提到的问题,但它会发现其他几个问题。例如,如果主题或样式调用3D类型边框,则会绘制2条边框线,并且您的计算更多地依赖于航位推算。
接下来,如果您尝试覆盖默认行为,我不确定Control.DrawBorder
是否完全合适。这将尊重由您试图覆盖的主题/样式等确定的某些事物。
我还可以使用TextRenderer
来更好地显示标题。
要做你想做的事,你可能不得不接管default GroupBoxRenderer
所做的一切。如果你将bordercolor更改为White或Fuschia之类的东西,你会发现正常的渲染仍在进行,你的代码只是试图绘制它的顶部。
即使您此正在运行,FlatStyle
,Color
,主题或样式的某些其他组合也会失败,因为您的代码正在运行没有考虑到这一点。
这是我使用过的,但它只是导致了一场有着不同问题的Whack-A-Mole游戏:
Dim textRect As New Rectangle With {.X = 0,
.Y = 2,
.Height = textSize.Height,
.Width = (textSize.Width - blankWidthSpace)
}
Dim borderRect As New Rectangle With {.X = 1, .Y = (textSize.Height \ 2) + 1,
.Width = Bounds.Width - 2,
.Height = Bounds.Height - (textSize.Height \ 2) - 2}
TextRenderer.DrawText(e.Graphics, " " & MyBase.Text & " ", MyBase.Font,
textRect, MyBase.ForeColor, MyBase.BackColor)
这似乎与您的other question有关“丑陋的白色边框”有关。尝试通过继承(一堆)控件来修复或覆盖主题并不是最好的方法。
我会考虑提供符合您口味的备用Aero主题。此外,你是谁说所有用户都同意它是“丑陋的”(我认为它使表格看起来很忙但不完全“丑陋”)。