调整窗口大小时,在 OnPaint() 上绘制会产生残留物

Dam*_*les 0 c# winforms

我创建了一个自定义面板,用于绘制边框(包含两个矩形)。问题是,如果我调整窗口大小,仍然会有残留物……很像 Windows XP 的纸牌动画。请参阅下面的屏幕截图。我向右调整了窗口的大小。

出了什么问题,我该如何解决?

向右调整窗口大小

protected override void OnPaint(PaintEventArgs e)
{
    var outer = ClientRectangle;
    outer.Width -= 1;
    outer.Height -= 1;
    var inner = outer;
    inner.X++;
    inner.Y++;
    inner.Width -= 2;
    inner.Height -= 2;

    e.Graphics.DrawRectangle(DarkPen, outer);
    e.Graphics.DrawRectangle(WhitePen, inner);

    base.OnPaint(e);
}
Run Code Online (Sandbox Code Playgroud)

更新

一开始我以为是因为我没有删除之前绘制的矩形。于是我打电话FillRectangle删除里面。

var contentArea = inner;
contentArea.X++;
contentArea.Y++;
contentArea.Width -= 2;
contentArea.Height -= 2;
e.Graphics.FillRectangle(SystemBrushes.Control, contentArea);
Run Code Online (Sandbox Code Playgroud)

但它也不起作用。似乎控件只绘制新扩展的部分,而不是整个区域。

Han*_*ant 5

Form 类被优化为一个容器控件。容器通常只需要绘制背景颜色。所以,正如您所注意到的,确实“只绘制新扩展的部分”。或者更准确地说,它不会覆盖之前的像素,很容易从产生的涂抹效果中识别出来。当您调整窗口大小时,使 Winforms 设计更加生动是一种有点微弱的尝试,当表单具有很多控件时,绘画会成为一个瓶颈,这非常明显。

您必须将其 ResizeRedraw 属性设置为 true,以便在必要时重绘其整个表面。当绘图代码变得复杂并且您开始注意到闪烁时,将 DoubleBuffered 属性设置为 true 也可能不会受到影响。

所以,大致:

    public Form1() {
        InitializeComponent();
        this.ResizeRedraw = true;
        this.DoubleBuffered = true;
    }
Run Code Online (Sandbox Code Playgroud)

优化 OnPaint() 通常不是一个有回报的策略,Windows 本身已经剪辑了您针对脏区域绘制的内容。

  • 您不指定区域,操作系统指定它。作为 e.ClipRectangle 属性传递给您。实际上使用它,嗯,很难与已经使用它的操作系统竞争。当绘图对象完全落在剪辑矩形之外时,您可以避免在自己的代码中接触大量数据。你所拥有的远远不够资格。 (2认同)