为什么我的WinForms控制闪烁并缓慢调整大小?

use*_*579 11 c# controls resize flicker winforms

我正在制作一个程序,我在面板中有很多面板和面板.

我在这些面板中有一些自定义绘制的控件.

1面板的调整大小功能包含用于调整该面板中所有控件的大小和位置的代码.

现在,只要我调整程序大小,此面板的调整大小就会激活.这导致该面板中的组件大量闪烁.

所有用户绘制的控件都是双缓冲的.

有人可以帮我解决这个问题吗?

Dan*_*Dan 19

要在调整win表单大小时消除闪烁,请在调整大小时暂停布局.覆盖表单resizebegin/resizeend方法如下.

protected override void OnResizeBegin(EventArgs e) {
    SuspendLayout();
    base.OnResizeBegin(e);
}
protected override void OnResizeEnd(EventArgs e) {
    ResumeLayout();
    base.OnResizeEnd(e);
}
Run Code Online (Sandbox Code Playgroud)

这将使控件保持原样(在调整大小之前),并在调整大小操作完成时强制重绘.


Cod*_*ray 17

查看您发布的项目,当您选择第一个选项卡时,使用渐变填充的组框时,闪烁非常糟糕.显示第二个或第三个标签时,几乎没有闪烁,如果有的话.

  你的主要表格

很明显,问题与您在该标签页上显示的控件有关.快速浏览自定义渐变填充组框类的代码可以提供更具体的原因.每次绘制一个groupbox控件时,你都会做很多非常昂贵的处理.因为每次调整表单大小时每个组框控件都必须重新绘制,所以该代码的执行次数难以置信.

此外,您将控件的背景设置为"透明",必须在WinForms中伪造,方法是让父窗口首先在控件窗口内绘制自己以生成背景像素.然后控制器将自己置于其上.这比使用纯色填充控件的背景更有效SystemColors.Control,并且在组框有机会自己绘制之前,它会让您在调整表单大小时看到正在绘制的表单像素.

这是我从您的自定义渐变填充组框控件类中讨论的特定代码:

protected override void OnPaint(PaintEventArgs e)
{
    if (Visible)
    {
        Graphics gr = e.Graphics;
        Rectangle clipRectangle = new Rectangle(new Point(0, 0), this.Size);
        Size tSize = TextRenderer.MeasureText(Text, this.Font);
        Rectangle r1 = new Rectangle(0, (tSize.Height / 2), Width - 2, Height - tSize.Height / 2 - 2);
        Rectangle r2 = new Rectangle(0, 0, Width, Height);
        Rectangle textRect = new Rectangle(6, 0, tSize.Width, tSize.Height);

        GraphicsPath gp = new GraphicsPath();
        gp.AddRectangle(r2);
        gp.AddRectangle(r1);
        gp.FillMode = FillMode.Alternate;

        gr.FillRectangle(new SolidBrush(Parent.BackColor), clipRectangle);

        LinearGradientBrush gradBrush;
        gradBrush = new LinearGradientBrush(clipRectangle, SystemColors.GradientInactiveCaption, SystemColors.InactiveCaptionText, LinearGradientMode.BackwardDiagonal);
        gr.FillPath(gradBrush, RoundedRectangle.Create(r1, 7));

        Pen borderPen = new Pen(BorderColor);
        gr.DrawPath(borderPen, RoundedRectangle.Create(r1, 7));
        gr.FillRectangle(gradBrush, textRect);
        gr.DrawRectangle(borderPen, textRect);
        gr.DrawString(Text, base.Font, new SolidBrush(ForeColor), 6, 0);
    }

}

protected override void OnPaintBackground(PaintEventArgs pevent)
{
    if (this.BackColor == Color.Transparent)
        base.OnPaintBackground(pevent);
}
Run Code Online (Sandbox Code Playgroud)

现在您已经看到了代码,红色警告标志应该会上升.你正在创建一堆 GDI +对象(画笔,笔,区域等),但没有Dispose任何一个!几乎所有代码都应该包含在using语句中.这只是草率的编码.

完成所有这些工作会花费一些成本.当计算机被迫花费大量时间来渲染控件时,其他事情就落后了.你看到一个闪烁,因为它紧张调整以跟上调整大小.它与计算机重载的任何其他东西没有什么不同(比如计算pi的值),当你使用像这里一样多的自定义绘制控件时,这样做真的很容易.Win32中的透明度很难,很多自定义3D绘画也是如此.它使UI看起来用户感觉笨拙.另一个原因是我不理解本土控制的匆忙.

你真的只有三个选择:

  1. 处理闪烁.(我同意,这不是一个好的选择.)
  2. 使用不同的控件,如标准的内置控件.当然,他们可能没有花哨的渐变效果,但如果用户已经定制了他们的Windows主题,那么无论如何,这种情况看起来会被打破一半.在深灰色背景上阅读黑色文字也相当困难.
  3. 更改自定义控件中的绘制代码以减少工作量.您可以通过一些简单的"优化"来完成,这些优化不会让您失去任何视觉效果,但我怀疑这不太可能.这是速度和眼睛糖果之间的权衡.什么都不做总是更快.


HAB*_*JAN 1

也许对您来说一个好的解决方案是使用Form.ResizeBeginForm.ResizeEnd事件。

在 ResizeBegin 上将主面板可见性设置为 false,在 ResizeEnd 上将主面板可见性设置为 true。

这样,当有人调整您的表单大小时,面板就不会被重新绘制。