【问题标题】:VB.NET Custom Control (custom drawing) Refresh issueVB.NET 自定义控件(自​​定义绘图)刷新问题
【发布时间】:2012-06-10 13:17:01
【问题描述】:

我创建了一个包含 2 个项目的简单解决方案。第一个项目(类库)包含一个名为 Container 的自定义控件,它使用圆角绘制自身。第二个项目(windows forms)是一个测试应用程序。

如果我在第二个项目的主窗体中添加一个 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

【问题讨论】:

    标签: vb.net controls gdi+


    【解决方案1】:

    这是你的问题:

    Dim r As Rectangle = e.ClipRectangle
    

    改成:

    Dim r As Rectangle = Me.ClientRectangle
    

    【讨论】:

      【解决方案2】:

      在我看来,您的 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;
          }
      }
      

      【讨论】:

        【解决方案3】:

        这里没有必要强制重绘(在正常情况下),因为一旦您的控件被轻推,重绘就会自动强制执行。

        但是,您需要做的是在绘制任何其他内容之前清除控件的背景:否则,您的绘制操作将与之前的绘制过程混合。只需添加一个

        e.Graphics.Clear(BackColor)
        

        Paint 事件处理程序中的其他绘图操作之前。此外,请考虑使用OnPaint 方法而不是Paint 事件,因为您将控件子类化并且不需要诉诸Paint 事件处理程序。

        为了记录,Refresh 强制同步重绘,这通常是不希望的。而是使用Invalidate,它将重绘请求排入默认窗口消息队列。

        【讨论】:

        • 调用 Graphics.Clear 仍然不能真正解决问题......这就是发生的事情:img300.imageshack.us/my.php?image=drawmessjp0.jpg
        • ropstah:在您的图片中,背景没有被清除。添加清除代码后,您是否重新编译项目?那么它应该看起来不同。但是,IDE 需要重新编译才能注意到更改!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-28
        • 2010-09-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多