• C#中控件Control的Paint事件和OnPaint虚函数的区别


      句柄 : 句柄,是整个Windows编程的基础。一个句柄是指使用的一个唯一的整数值,即一个4字节(64位程序中为8字节)长的数值,来标识应用程序中的不同对象和同类对象中的不同的实例,诸如,一个窗口,按钮,图标,滚动条,输出设备,控件或者文件等。应用程序能够通过句柄访问相应的对象的信息,但是句柄。
        重写 : 当一个子类继承一父类,而子类中的方法与父类中的方法的名称,参数个数、类型都完全一致时,就称子类中的这个方法重写了父类中的方法。
        函数 : 函数(function),最早由中国清朝数学家李善兰翻译,出于其著作《代数学》。之所以这么翻译,他给出的原因是“凡此变数中函彼变数者,则此为彼之函数”,也即函数指一个量随着另一个量的变化而变化,或者说一个量中包含另一个量。
        代码 : 代码就是程序员用开发工具所支持的语言写出来的源文件,是一组由字符、符号或信号码元以离散形式表示信息的明确的规则体系。代码设计的原则包括惟一确定性、标准化和通用性、可扩充性与稳定性、便于识别与记忆、力求短小与格式统一以及容易修改等。 源代码是代码的分支,某种意义上来说。

      两种方法是有区别的:
      用Paint事件绘制窗体(如在窗体绘制椭圆)时,会被基类OnPaint虚方法所调用,而重写OnPaint方法绘制窗体时则通过调用代码base.OnPaint(e);调用基类的虚方法,从而间接调用基类预先定义好的Paint事件。

    OnPaint虚方法的主要代码原形应该类似以下形式(从中便可以看出):

    protected virtual OnPaint(PaintEventArgs e)
    { 
    if(paint != null)
    { 
    paint(this,e);
    }
    }

    如果直接重写OnPaint虚函数,Paint事件就会失效。但是如果下面这样重写Paint事件就不会失效:

    代码如下:
    protected override OnPaint(PaintEventArgs e)
    {  
    base.OnPaint(e);  //自己的代码
    }

    (一)重绘时候经常会用到OnPaint()和Paint,它们有什么区别呢?

    1.OnPaint方法是对一个控件来说的;而Paint事件是对一个控件对象来说的。它们中前者相当于是类的一个成员函数,而后者相当于是类的一个函数指针类型的变量(会因对象的不同而不同)。    
    2.OnPaint方法引发Paint事件,所以重写OnPaint方法,一定要调用base.OnPaint,否则就不会引发Paint事件了。OnPaint原形应该类似以下形式(从中便可以看出):

    代码如下:
    protected virtual void OnPaint(PaintEventArgs e)
            {
                if (this.Paint != null)
                {
                    this.Paint(this,e);
                }
            }

    3.从实例中观察二者调用顺序

    代码如下:
    private void Form1_Paint(object sender, PaintEventArgs e)
            {
                test t = new test();
                t.AntiAlias = true;
                t.SetColor(test.eShapeColor.Circle1FillColor, Color.DarkCyan);
                e.Graphics.DrawImageUnscaled(t.Image, 10, 10);
            }
            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);//引发Paint事件处理(处理该事件时候调用Form1_Paint方法)
                ..........
            }

    Form1_Paint()只是处理Paint事件的方法,也可将它的四行代码在OnPaint方法中写,此时可以不写base.OnPaint(e),即不引发事件处理,也可达到同样的效果。

    (二)那么应分别在什么情况下使用它们呢? 
    1.如果想对所有控件都按照某种固定的方式显示,如:自己写控件时,则需要修改重载控件的OnPaint方法;而如果仅仅在某个环境下,对某个对象要做不同的显示,则只需在其的Paint事件中做即可。

    2.在实现派生类的时候,遵循 C# 原则35:选择重写函数而不是使用事件句柄。

    许多.net类库中的类都提供了两种不同的处理事件句柄的方法。既可以为其添加事件,也可以重写其基类的事件抽象方法。在实现派生类的时候,更好的选择是重写基类中的抽象方法。

    因为这样,一旦事件句柄抛出异常,不会再有其他的事件句柄被调用。这避免了一些错误代码继续被调用而引发的问题。通过重写受保护的虚方法,我们的句柄可以 第一个被调用。基类中虚函数负责其他相关句柄的调用。这意味着如果需要调用那些事件句柄(一般来说是需要的),就要调用基类的虚函数。在有些特殊情况下我 们需要替换基类的默认行为,可能不需要调用任何原有的事件句柄。虽然我们不能保证所有的事件句柄都被执行,因为其可能会抛出异常,但是我们可以保证派生类 的行为是正确的。

    使用override比添加事件句柄高效的多。在 条款 22中展示了System.Windows.Forms.Control类是如何存储句柄时间并将其对应到每一个事件的。这种事件机制由于要检查事件句柄将造成更多的消耗。事件句柄列表中的每个方法都需要执行。相比重写虚方法,通过事件处理会消耗更多的时间。

    此外,重写虚方法只需要维护一个函数就可以达到检查和修改的目的,代码更清晰。而事件机制需要两个维护点:事件句柄函数和事件绑定代码。其中任何一点都可能造成整体功能上的失败。一个函数显然要简单些。

    总结:

    OnPaint是Control类中的方法,Paint是事件,Paint是用于改变部分显示用比较合适,实际上Paint事件在OnPaint中被调用,如果你重写OnPaint但是不调用base.OnPaint(e);的话Paint事件就失效了,所以对于自定义控件而言要改变外观重写OnPaint更合适,一般情况下绘制图形编写Paint事件的处理方法就行。

    小提示:

    1、做小游戏的话,用PictureBox代替Panel做绘图板面比较合适,因为默认双缓冲,不容易闪。

    2、Control.Refresh  Control.Invalidate 和 Control.OnPaint之间的联系和区别:

      1)、Control.Invalidate会放一个WM_PAINT消息到消息队列,当Control处理到该消息的时候,就调用OnPaint。
      2)、Control.Refresh相当于以下两行:
        Control.Invalidate(true);
        Control.Update();
      3)、Control.Update会搜索消息队列,如果找到WM_PAINT,就把它取出,'直接'调用OnPaint。
      因此,Invalidate告诉系统当前窗口要求重画,但不要求立即执行,那些排在WM_PAINT前面的消息会先处理。
      Refresh则立刻重画窗口。

    参考链接:

    1、C#中Form的Paint事件响应方法与重载虚方法OnPaint()的区别

    2、重写 OnPaint 方法

  • 相关阅读:
    在ASP.NET WebAPI 中使用缓存【Redis】
    Redis 缓存服务配置与使用
    使用 New Relic 监控接口服务性能 (APM)
    基于OWIN WebAPI 使用OAuth授权服务【客户端模式(Client Credentials Grant)】
    svn查看代码作者的命令
    Failed to execute goal org.codehaus.mojo:rpm-maven-plugin:2.1.1:rpm (default) on project **
    Error: Cannot find a valid baseurl for repo: base
    intellij中编译报错: The packaging for this project did not assign a file to the build artifact
    fsimage 和 edits log
    查看rpm和war包内容
  • 原文地址:https://www.cnblogs.com/rainbow70626/p/4749369.html
Copyright © 2020-2023  润新知