14

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

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

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

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

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

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

4

8 回答 8

23

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

protected override void OnResizeBegin(EventArgs e) {
    SuspendLayout();
    base.OnResizeBegin(e);
}
protected override void OnResizeEnd(EventArgs e) {
    ResumeLayout();
    base.OnResizeEnd(e);
}

这将使控件保持不变(与调整大小之前一样)并在调整大小操作完成时强制重绘。

于 2011-10-13T20:18:01.413 回答
18

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

  你的主要形式

很明显,问题与您在该标签页上显示的控件有关。快速浏览一下自定义渐变填充组框类的代码会发现更具体的原因。每次绘制一个组框控件时,您都会进行大量非常昂贵的处理。因为每次调整窗体大小时每个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);
}

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

做所有这些工作需要付出一些代价。当计算机被迫花费如此多的时间来渲染控件时,其他事情就落后了。您会看到闪烁,因为它会紧跟调整大小。它与其他任何使计算机过载的东西没有什么不同(比如计算 pi 的值),当您像这里一样使用尽可能多的自定义绘制控件时,这样做真的很容易。Win32 中的透明度很难,很多自定义 3D 绘画也是如此。它使用户界面看起来感觉很笨拙。还有一个原因是我不理解急于摆脱原生控件的情况。

你真的只有三个选择:

  1. 处理闪烁。(我同意,这不是一个好的选择。)
  2. 使用不同的控件,例如标准的内置控件。当然,它们可能没有花哨的渐变效果,但如果用户自定义了他们的 Windows 主题,那无论如何都会有一半的时间看起来很糟糕。在深灰色背景上阅读黑色文本也相当困难。
  3. 更改自定义控件中的绘画代码以减少工作量。您可以通过一些简单的“优化”来解决问题,这些优化不会花费您任何视觉效果,但我怀疑这不太可能。这是速度和视觉效果之间的权衡。什么都不做总是更快。
于 2011-01-14T14:19:31.740 回答
3

所以我遇到了同样的问题 - 我的透明背景控件重绘了 34 次,对我有用的是:

在我包含控件的表单上

protected override void OnResize(EventArgs e)
    {
        myControl.Visible = false;
        base.OnResize(e);
        myControl.Visible = true;
    }

在控件中也是如此:

protected override void OnResize(EventArgs e)
    {
        this.Visible = false;
        base.OnResize(e);
        this.Visible = true;
    }

这将重新绘制的数量减少到 4,这有效地消除了调整控件大小时的任何闪烁。

于 2011-12-15T22:49:52.227 回答
3

使用此代码调整表单大小时,我成功消除了闪烁。谢谢。

VB.NET

Public Class Form1

Public Sub New()
    Me.SetStyle(ControlStyles.UserPaint Or ControlStyles.OptimizedDoubleBuffer Or ControlStyles.AllPaintingInWmPaint Or ControlStyles.SupportsTransparentBackColor, True)
End Sub

Private Sub Form1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
    Me.Update()
End Sub

End Class

C#

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        Resize += Form1_Resize;
        this.SetStyle(ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.SupportsTransparentBackColor, true);
    }

    private void Form1_Resize(object sender, System.EventArgs e)
    {
        this.Update();
    }

}
于 2011-06-25T18:30:52.853 回答
1

Maybe a good solution for you will be to use Form.ResizeBegin and Form.ResizeEnd events.

On ResizeBegin set main panel visibility to false, on ResizeEnd set main panel visibility to true.

This way panels will not be redrawn while someone is resizing your form.

于 2011-01-14T12:11:49.210 回答
1

虽然挂钩到 ResizeBegin 和 ResizeEnd 是正确的想法,但我不会隐藏主面板的可见性,而是将任何调整大小计算延迟到 ResizeEnd。在这种情况下,您甚至不需要挂钩到 ResizeBegin 或 Resize - 所有逻辑都进入 ResizeEnd。

我这么说有两个原因。一,即使面板被隐藏,调整大小操作可能仍然很昂贵,因此除非调整大小计算被延迟,否则表单不会像应有的那样响应。第二,在调整大小时隐藏窗格的内容可能会让用户感到不安。

于 2011-05-10T23:32:33.537 回答
0

我有同样的问题。

这似乎是因为您使用的是圆角。当我将 CornerRadius 属性设置为 0 时,闪烁消失了。

到目前为止,我只找到了以下解决方法。不是最好的,但它可以阻止闪烁。

private void Form_ResizeBegin(object sender, EventArgs e)
{
  rectangleShape.CornerRadius = 0;
}

private void Form_ResizeEnd(object sender, EventArgs e)
{
  rectangleShape.CornerRadius = 15;
}
于 2014-10-09T20:34:13.487 回答
0

我有一个类似的问题。我的整个表单都在慢慢调整大小,并且控件以丑陋的方式绘制它们。所以这对我有帮助:

//I Added This To The Designer File, You Can Still Change The WindowState In Designer View If You Want. This Helped Me Though.
this.WindowState = FormWindowState.Maximized;

并在调整大小事件中,将此代码添加到开头

this.Refresh();
于 2021-05-11T03:22:39.943 回答