为什么我的WinForms控件 Flink 和调整大小缓慢?

wbgh16ku  于 2023-04-21  发布在  Flink
关注(0)|答案(9)|浏览(185)

我在做一个程序,里面有很多面板和面板中的面板。
我在这些面板中有一些自定义绘制的控件。
1面板的调整大小功能包含调整该面板中所有控件的大小和位置的代码。
现在只要我调整程序的大小,这个面板的大小就会被激活。这会导致这个面板中的组件出现大量 Flink 。
所有用户绘制的控件都是双缓冲的。
有人能帮我解决这个问题吗?

bnl4lu3b

bnl4lu3b1#

要消除在调整win窗体大小时的 Flink ,请在调整窗体大小时暂停布局。

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

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

des4xlb0

des4xlb02#

看看你发布的项目,当你选择第一个标签时, Flink 非常糟糕,有渐变填充的组框。当第二个或第三个标签显示时,几乎没有任何 Flink ,如果有的话。

很明显,问题与选项卡页面上显示的控件有关。快速浏览一下自定义渐变填充的group box类的代码,就会发现更具体的原因。每次绘制其中一个group box控件时,您都要进行 * 大量 * 非常昂贵的处理。因为 * 每个 * groupbox控件都必须在每次调整窗体大小时重新绘制自己,这段代码被执行了无数次

  • 另外 *,你有控件的背景设置为“透明”,这必须在WinForms中通过要求父窗口首先在控件窗口内绘制自己来产生背景像素来伪造。控件然后在上面绘制自己。这也比用纯色(如SystemColors.Control)填充控件的背景要多。它会导致你在调整窗体大小时看到窗体的像素被绘制,而groupbox还没有机会自己绘制。

下面是我所讨论的自定义渐变填充groupbox控件类的具体代码:

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其中任何一个!**几乎所有 * 代码都应该 Package 在using语句中。这只是草率的编码。
做所有这些工作都是要付出代价的。当计算机被迫花这么多时间来呈现控件时,其他事情就会滞后。你会看到它在努力跟上调整大小时出现 Flink 。这和其他让计算机过载的事情没有什么不同(如计算pi的值),当你像这里一样使用许多自定义绘制控件时,很多自定义3D绘画也是如此。它让用户感觉UI看起来很笨重。这也是我不理解为什么人们会匆忙放弃原生控件的另一个原因。
你只有三个选择:
1.处理 Flink 。(我同意,这不是一个好的选择。)
1.使用不同的控件,比如标准的内置控件。当然,它们可能没有花哨的渐变效果,但如果用户自定义了Windows主题,那么无论如何有一半的时间看起来都很糟糕。在深灰色背景上阅读黑色文本也相当困难。
1.更改自定义控件中的绘画代码以减少工作量。您可能可以通过一些简单的“优化”来获得,而不会花费您任何视觉效果,但我怀疑这不太可能。这是速度和视觉糖果之间的权衡。什么都不做总是更快。

e37o9pze

e37o9pze3#

我成功地消除 Flink 时,窗体调整大小使用此代码.谢谢.
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();
    }

}
uidvcgyl

uidvcgyl4#

所以我遇到了同样的问题--我的透明背景控件被重新绘制了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次,从而有效地消除了调整控件大小时的任何 Flink 。

snvhrwxg

snvhrwxg5#

也许一个好的解决方案是使用Form.ResizeBeginForm.ResizeEnd事件。
在ResizeBegin上将主面板可见性设置为false,在ResizeEnd上将主面板可见性设置为true。
这样,当有人调整窗体大小时,面板将不会重新绘制。

kpbwa7wx

kpbwa7wx6#

虽然挂钩到ResizeBegin和ResizeEnd是正确的想法,而不是隐藏主面板的可见性,而是延迟任何调整大小的计算,直到ResizeEnd。在这种情况下,你甚至不需要挂钩到ResizeBegin或Resize -所有的逻辑进入ResizeEnd。
我这么说有两个原因。第一,即使面板是隐藏的,调整大小的操作可能仍然是昂贵的,因此,除非调整大小的计算被延迟,否则表单不会像它应该的那样响应。第二,在调整大小时隐藏窗格的内容可能会让用户感到不舒服。

lsmepo6l

lsmepo6l7#

我也有同样的问题。
这似乎是因为你使用了圆角。当我将CornerRadius属性设置为0时, Flink 消失了。
到目前为止,我只找到了以下的变通方法。不是最好的一个,但它停止了 Flink 。

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

private void Form_ResizeEnd(object sender, EventArgs e)
{
  rectangleShape.CornerRadius = 15;
}
92dk7w1h

92dk7w1h8#

我也遇到过类似的问题。我的整个窗体调整缓慢,控件以难看的方式绘制它们。所以这对我有帮助:

//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;

在Resize事件中,将此代码添加到开头

this.Refresh();
kiz8lqtg

kiz8lqtg9#

Flink 与挂起布局、恢复布局、调整大小、刷新或此处列出的任何答案无关。要减少 Flink ,只需确保控件是在面板中作为容器创建的,而不是直接在窗体中创建的。当控件直接在窗体中创建而没有容器时,窗体将 Flink 与这些控件的数量相同的次数。如果没有,则窗体将 Flink 。当调整窗体大小时(不仅通过_Resized事件处理程序,还通过代码),窗体 Flink 的次数仅为窗体中面板的数量加上直接添加到窗体的所有控件的数量。
关于这个问题,我认为 Flink 的主要原因是由于代码中的调整大小控件,这导致所有其他面板大小和面板中的所有控件。如果我们为面板设置锚点并为面板中的控件设置锚点,不需要通过代码调整面板大小或面板中控件的大小。面板中控件的锚是面板。面板中面板的锚点是包含面板。如果我们在窗体中正确地应用面板和锚点,则不需要调整面板中控件的大小。

相关问题