【问题标题】:How do I call paint event?如何调用绘画事件?
【发布时间】:2010-10-31 11:23:48
【问题描述】:

我的程序在其面板上绘制文本,但如果我想删除文本,我必须重新绘制。

如何手动调用(引发)绘制事件?

【问题讨论】:

    标签: c# .net winforms events


    【解决方案1】:

    在表单或控件的方法中,您有 3 个选择:

    this.Invalidate();  // request a delayed Repaint by the normal MessageLoop system    
    this.Update();      // forces Repaint of invalidated area 
    this.Refresh();     // Combines Invalidate() and Update()
    

    通常,您只需致电Invalidate() 并让系统将其与其他屏幕更新结合起来。如果你赶时间,你应该打电话给Refresh(),但是你冒着因为其他控件(尤其是父控件)无效而连续多次重新绘制它的风险。

    Windows(Win32 和 WinForms.Net)处理此问题的正常方式是等待MessageQueue 运行为空,然后处理所有无效的屏幕区域。这是有效的,因为当某些事情发生变化时,通常会级联到其他事情(控件)也发生变化。

    Update() 最常见的情况是当您在 for 循环中更改属性(例如 label1.Text,这将使标签无效)并且该循环暂时阻塞消息循环时。每当你使用它时,你应该问问自己是否不应该使用线程。但答案并不总是肯定的。

    【讨论】:

    • 我想澄清一下。 Update() 将立即重绘控件中已经失效的任何部分。您仍然需要先使无效。 Refresh() 将使整个控件无效并立即重新绘制。当我编写一个自己绘制的控件时,我使用脏矩形调用 Invalidate(),然后调用 Update() 以提高响应能力,并远离 Refresh() 以提高性能。
    • 请注意,根据您使用的方法,CPU 性能可能存在巨大差异。 this.Invalidate() 需要最少的 CPU 资源,因为您不会在标准消息循环之外强制执行任何操作,如果您可以调用 this.Invalidate(false) 则尤其如此,因此您只在主控件/表单上调用 OnPaint() 而不是子控件。对于我的一个 UserControl,从 this.Update() 移动到 this.Invalidate(false) 将 CPU 负载减少了 4 倍。
    【解决方案2】:

    Invalidate() 方法将导致重绘。

    MSDN Link

    【讨论】:

      【解决方案3】:

      我发现 Invalidate() 造成了太多的闪烁。这是我的情况。我正在开发的自定义控件通过处理 Paint 事件来绘制其全部内容

      this.Paint += this.OnPaint;
      

      这个处理程序调用一个自定义例程来进行实际的绘画。

      private void OnPaint(object sender, PaintEventArgs e)
      {
          this.DrawFrame(e.Graphics);
      }
      

      为了模拟滚动,我想在每次按下鼠标左键时光标移动时重新绘制控件。我的第一选择是使用 Invalidate(),如下所示。

      private void RedrawFrame()
      {
          var r = new Rectangle(
              0, 0, this.Width, this.Height);
      
          this.Invalidate(r);
          this.Update();
      }
      

      控件滚动正常,但闪烁远远超出任何舒适的水平。因此,我决定在处理 MouseMove 事件后直接调用我的自定义 DrawFrame() 方法,而不是重新绘制控件。这产生了没有闪烁的平滑滚动。

      private void RedrawFrame()
      {
          var g = Graphics.FromHwnd(this.Handle);
          this.DrawFrame(g);
      }
      

      这种方法可能并不适用于所有情况,但到目前为止它很适合我。

      【讨论】:

      • 小心,我认为 FromHwnd() 的结果应该再次被 Disposed (放在 using() {} 中)
      • 使用双缓冲消除闪烁。
      【解决方案4】:

      我想你也可以拨打Refresh()

      【讨论】:

        【解决方案5】:

        也许这是一个老问题,这就是为什么这些答案对我不起作用的原因......使用 Visual Studio 2019,经过一番调查,这是我找到的解决方案:

        this.InvokePaint(this, new PaintEventArgs(this.CreateGraphics(), this.DisplayRectangle));
        

        【讨论】:

          【解决方案6】:

          调用 control.invalidate 并引发绘制事件。

          【讨论】:

          • private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { System.Drawing.Graphics graphics = this.CreateGraphics(); System.Drawing.Rectangle 矩形 = new System.Drawing.Rectangle(0, 0, 50, 50); graphics.DrawEllipse(System.Drawing.Pens.Black, rectangle); graphics.DrawRectangle(System.Drawing.Pens.Red, 矩形);什么时候调用这个paint方法来重绘表单。它确实会重新绘制表单,不是吗。
          【解决方案7】:

          根据上下文,刷新也可能使代码更具可读性。

          【讨论】:

            【解决方案8】:

            使用Control.InvokePaint也可以用于手动双缓冲

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2018-03-19
              • 1970-01-01
              • 2017-10-20
              • 2015-01-22
              • 1970-01-01
              • 2018-04-08
              • 1970-01-01
              相关资源
              最近更新 更多