我用2个项目创建了一个简单的解决方案。第一个项目(类库)包含一个名为Container的自定义控件,它使用圆角绘制自己。第二个项目(windows窗体)是一个测试应用程序。
如果我在第二个项目的主窗体中添加一个Container实例,它会很好地显示圆角。另外,当我运行第二个项目时,我可以看到容器。
然而,当我开始移动表格(点击并按住标题栏)时,特别是当我快速移动时,所有的绘图都搞砸了,一遍又一遍地绘制但是没有先清除它的表面......
我可以在Form1.Move事件中调用Container1.Refresh(),但我不想每次都设置它,因为这也意味着我必须在Form1.Resize
事件中调用Container1.Refresh()谁知道哪个事件......
Container(控件)类本身是否有一个事件,我应该调用Me.Refresh()或Me.Update()或Me.Invalidate()?
供参考(Form1.vb)
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
End Sub
Private Sub Form1_Move(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Move
Me.Container1.Refresh()
End Sub
End Class
供参考(Container.vb):
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Drawing.Drawing2D
Public Class Container : Inherits Control
Private _Gp As GraphicsPath
Private Sub Container_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
Dim r As Rectangle = e.ClipRectangle
Dim gp As New GraphicsPath
Dim cs As Integer = 25 'CornerSize'
r.Inflate(-5, -5)
gp.AddArc(r.X, r.Y, cs, cs, 180, 90)
gp.AddArc(r.X + r.Width - cs, r.Y, cs, cs, 270, 90)
gp.AddArc(r.X + r.Width - cs, r.Y + r.Height - cs, cs, cs, 0, 90)
gp.AddArc(r.X, r.Y + r.Height - cs, cs, cs, 90, 90)
Dim t As Single = cs / 2 + r.Y
gp.AddLine(r.X, r.Y + r.Height - cs, r.X, t)
e.Graphics.SmoothingMode = Drawing.Drawing2D.SmoothingMode.AntiAlias
e.Graphics.DrawPath(Pens.Black, gp)
End Sub
End Class
答案 0 :(得分:4)
这是你的问题:
Dim r As Rectangle = e.ClipRectangle
将其更改为:
Dim r As Rectangle = Me.ClientRectangle
答案 1 :(得分:3)
在我看来,好像你的Container
类没有绘制整个区域 - 通常控件负责绘制整个矩形。
为了让控件不执行此操作 - 具有透明区域(如圆角) - 您需要为控件提供WS_EX_TRANSPARENT
属性。请注意,这是一个Windows API主题,而不是.NET主题,所以你正朝着一些小巫术的方向发展。
虽然它是用C#编写的,但CodeProject文章Making Transparent Controls with C# and .NET 3.5似乎与你想要实现的目标直接相关。
要引用该文章,首先需要覆盖UserControl的构造函数并配置背景:
public TranspControl()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.Opaque, true);
this.BackColor = Color.Transparent;
}
然后,您需要覆盖CreateParams()
方法来设置控件样式WS_EX_TRANSPARENT
:
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20;
return cp;
}
}
答案 2 :(得分:1)
没有必要强制重绘(在正常情况下),因为一旦你的控件被轻推就会自动强制重绘。
但是,你需要做的是在绘制其他任何内容之前清除控件的背景:否则,你的绘画操作将与之前的绘画过程混合。只需添加一个
e.Graphics.Clear(BackColor)
在Paint
事件处理程序中的其他绘图操作之前。另外,考虑使用OnPaint
方法而不是Paint
事件,因为您对控件进行了子类化,并且不需要来诉诸Paint
事件处理程序。 / p>
对于记录,Refresh
强制执行通常不需要的同步重绘。而是使用Invalidate
将重绘请求排入默认窗口消息队列。