C#中的Invalidate方法未调用paint方法

7

我已经重写了OnPaint方法,以在屏幕上画一个椭圆。

    protected override void OnPaint(PaintEventArgs e)
    {
        MessageBox.Show("Paint");
        if (debugStarted)
        {
            int y = rtbLogicCode.PlaceToPoint(new Place(0, debugLine)).Y;
            if (rtbLogicCode.GetVisibleState(debugLine).ToString() == "Visible")
            {
                e.Graphics.FillEllipse(new LinearGradientBrush(new Rectangle(0, y, 15, 15), Color.LightPink, Color.Red, 45), 0, y, 15, 15);
            }
            base.OnPaint(e);
        }
    }

    private void rtbLogicCode_Scroll(object sender, ScrollEventArgs e)
    {
        this.Invalidate();
    }

滚动事件(在Richtextbox上)已经得到了正确处理,但是即使我无效化了表单,它也没有调用OnPaint函数(消息框没有显示)。

可能的原因是什么?

编辑:我忘记提到,在我的子窗体初始化函数中(作为主窗体的控件添加使用MDI属性),我设置了以下样式:

 private void LogicCodeInit()
    {


            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.UserPaint, true);


    }

编辑2:我还忘记提到子表单被添加为TabControl的一个控件。然后TabControl作为主界面的一个控件被添加。

你确定已经调用了 this.Invalidate() 吗?如果通过调整窗口大小来强制重绘,会发生什么? - sloth
我确定已经调用了invalidate(我也在消息框中检查过)。当我调整窗口大小时,什么也没有发生。 - TtT23
3个回答

13

在调用Invalidate方法后,请调用Update方法。Invalidate方法只会重新绘制具有焦点的表单,由于它被添加为TabControl子元素,因此可能无法获取焦点。

来自MSDN文档

调用Invalidate方法不会强制同步绘制;要强制同步绘制,请在调用Invalidate方法后调用Update方法。当没有参数调用此方法时,整个客户区域都将添加到更新区域中。


Invalidate 应该导致窗体重新绘制,而不管它是否具有焦点,只是不会立即重绘。你引用文档中也没有提到焦点。 - user743382
重点是基于经验而非文档的 :-) - Jcl
我的经验(现在为了这个问题再次测试)表明,无论失效的控件是否具有焦点,Invalidate都会触发OnPaint。我正在单击Form1上的一个按钮,该按钮使Form2失效。 - user743382
我在其他一些项目中有不同的经验。条件可能有所不同...但无论如何,Invalidating 不需要实际更新表格。它只是提示应该更新什么。如果它永远不会被更新,那么原始问题可能会发生。测试 Update 是否确实更新了表格,至少不会造成伤害。 - Jcl
同意,这是一个简单的测试,最坏的情况下可能会导致减速或闪烁,但考虑到双缓冲,这两种情况都不应该引起注意。 - user743382

1

在IT相关的内容中,调用控件上的Invalidate方法会使其无效化,并指示其需要进行更新“某个时候”,但不会立即进行更新。调用Update将立即重新绘制控件中任何已被无效化的部分。调用Refresh将结合以上效果。每当系统处于空闲状态时,它都会为具有任何无效区域的控件调用处理更新。

Invalidate方法在连续执行许多更改控件内容的方法的情况下非常有用。与在每个更改控件的方法之后重绘控件不同,可以使更改控件的方法使那些需要重新绘制的部分无效。完成可能更改控件的所有方法后,然后可以使用Update来重新绘制已被无效化的控件部分(如果有)。如果重新绘制控件需要1/100秒,并且需要对其执行五十个操作,则推迟和整合更新可能会使控件看起来瞬间更新和花费半秒钟之间有所差异。


0
主要原因是如果你的控件样式(ControlStyle)不包含UserPaint,那么OnPaint可能不会被调用。如果您设置了UserPaint但没有提到它,我会期望你提到的,所以我假设你没有设置。在这种情况下,在您的构造函数中添加对SetStyle的调用。

我完全忘记提到这一点,但我已经添加了以下样式调用: this.SetStyle(ControlStyles.DoubleBuffer, true); this.SetStyle(ControlStyles.ResizeRedraw, true); this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); this.SetStyle(ControlStyles.UserPaint, true); - TtT23
顺便说一句,我的回答中的 GetStyle 部分本来就是错误的,我已经将其删除了。 - user743382
当我设置断点时,调试器从未进入OnPaint函数。 我不知道这是否有关系,但如上所述,OnPaint方法被子窗口覆盖,而不是主窗口(设为MDIParent)。 绘画方法只会在主窗口上调用吗? 调试器从未进入OnPaint函数当我设置断点。 我不知道这是否有关系,但是正如上面所说的那样,OnPaint方法被子窗口覆盖了,而不是主窗口(设置为MDIParent)。 绘画方法只会在主窗口上调用吗? - TtT23
我现在意识到了一件非常重要的事情,我所说的表单实际上是作为TabControl的一个控件添加的。然后将TabControl作为一个控件添加到主表单中。我认为这改变了很多东西,也许无效化必须在TabControl本身上完成,而不是在表单上完成。我的理解正确吗? - TtT23
我创建了一个简单的测试项目,我的 OnPaint 没有问题地触发,并且我绘制的内容是可见的。如果我添加一个调用 form2.Invalidate() 的按钮,当我点击该按钮时,它也会被重新绘制。你能否创建一个最小化的项目来展示你遇到的问题? - user743382
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接