在执行所有更新之前,我可以暂停表单的重绘吗?

发布于 2024-07-14 09:49:36 字数 318 浏览 8 评论 0原文

使用 C# 和 .Net 2.0,我使用不规则形状的表单(TransparencyKey、FormBorderStyle = None 等),并希望允许“正常”边框模式。

我将背景颜色从石灰更改为默认颜色 我将 FormBorderStyle 更改为 FixSingle 我将 TransparencyKey 更改为 Colour.None

不幸的是,这在屏幕上看起来一团糟,图像向下和向侧面跳跃了几个像素,形成石灰绿色。

我认为这是由于在每行代码后重新绘制表单造成的,是否可以暂停绘制表单,直到我进行更改,然后重新绘制表单一次?

G

Using C# and .Net 2.0, I'm using an irregularly shaped form (TransparencyKey, FormBorderStyle = None, etc...) and want to allow "normal" bordered mode.

I change the back colour to default from Lime
I change FormBorderStyle to FixedSingle
I change the TransparencyKey to Colour.None

Unfortuanately this looks a complete mess on screen with the image jumping a few pixels down and to the side and Lime green form.

I think this is caused by the form being redrawn after each line of code, is it possible to suspend drawing the form until I have made my changes and then just redraw the form once?

G

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

写下不归期 2024-07-21 09:49:36

新答案:在应用新的窗口属性时覆盖 WndProc 并阻止 WM_PAINT 消息。

旧答案:覆盖 WndProc,并阻止 WM_ERASEBKGND 消息。

以下代码的作用说明:

当窗口区域无效时,Windows 会向控件发送一系列消息,从而生成新绘制的小部件。 本系列的早期消息是 WM_ERASEBKGND。 通常,为了响应此消息,控件将自身绘制为纯色。 随后,响应 WM_PAINT 消息(通常由我们在 OnPaint 事件中使用),实际绘制完成。 如果这张图很重要,那么在更新小部件之前将会有延迟,并且您会遇到烦人的闪烁。

再次查看您的代码,我显然正在解决一个不同的问题。 尝试这个新示例。 如果未设置 bAllowPaint 标志,它将阻止窗体/控件的绘制。

示例:

    private const int WM_PAINT = 0x000F;

    protected override void WndProc(ref Message m)
    {
        if ((m.Msg != WM_PAINT) ||
            (bAllowPaint && m.Msg == WM_PAINT))
        {
            base.WndProc(ref m);
        }
    }

示例:

    private const int WM_ERASEBKGND = 0x0014;

    protected override void WndProc(ref Message m)
    {
        if (m.Msg != WM_ERASEBKGND) // ignore WM_ERASEBKGND
        {
            base.WndProc(ref m);
        }
    }

NEW answer: Override the WndProc and block the WM_PAINT message while you apply the new Window properties.

OLD answer: Override the WndProc, and block the WM_ERASEBKGND message.

Explanation of what the code below does:

When a window's region is invalidated, Windows sends a series of messages to the control that result in a freshly-painted widget. An early message in this series is WM_ERASEBKGND. Normally, in response to this message, the control paints itself a solid color. Later, in response to the WM_PAINT message (which is usually consumed by us in the OnPaint event) the actual drawing is done. If this drawing is non-trivial there will be a delay before the widget is updated and you'll get an annoying flicker.

Looking at your code again I was clearly solving a different problem. Try this new example. It will block the painting of the form/control if the bAllowPaint flag is unset.

The NEW example:

    private const int WM_PAINT = 0x000F;

    protected override void WndProc(ref Message m)
    {
        if ((m.Msg != WM_PAINT) ||
            (bAllowPaint && m.Msg == WM_PAINT))
        {
            base.WndProc(ref m);
        }
    }

The OLD example:

    private const int WM_ERASEBKGND = 0x0014;

    protected override void WndProc(ref Message m)
    {
        if (m.Msg != WM_ERASEBKGND) // ignore WM_ERASEBKGND
        {
            base.WndProc(ref m);
        }
    }
樱&纷飞 2024-07-21 09:49:36

尝试 Form.DoubleBuffered 属性。 将其设置为“真”。

另外,如果您的表单有任何子控件,也请将这些子控件的 DoubleBuffered 设置为 true(以及子控件的子控件,等等)。

最后,在更改之前调用 SuspendLayout,然后调用 ResumeLayout。 请记住,这只会影响子控件的放置。 如果您正在进行任何自定义绘图,DoubleBuffered 属性将为您带来更多性价比。

Try the Form.DoubleBuffered property. Set it to 'true'.

Also, if your form has any child controls, also set DoubleBuffered to true for those as well (and children's children, etc, down the line).

Lastly, call SuspendLayout before your changes and ResumeLayout afterwards. Keep in mind this only affects placement of child controls. If you are doing any custom drawing the DoubleBuffered property will give you more bang for the buck.

顾铮苏瑾 2024-07-21 09:49:36

您正在修改对表单有相当大影响的属性。 TransparencyKey 和 FormBorderStyle 需要更改窗口样式位。 Windows 不允许更改这些样式位。 Windows 窗体通过完全销毁窗口并从头开始重新创建它来实现它们。 巧妙的技巧,但这需要时间,并且每次更改样式时都会重新绘制表单。 造成您看到的令人不愉快的视觉效果。

尝试这个:
1. 将不透明度设置为0,使表单变得不可见
2.更改BackColor,没问题
3. 更改 FormBorderStyle,重新创建窗口
4. 更改 TransparencyKey,重新创建窗口
5. 将不透明度更改为 1,窗口将重新创建,然后可见

例如:

  this.Opacity = 0;
  this.BackColor = Color.FromKnownColor(KnownColor.Control);
  this.FormBorderStyle = FormBorderStyle.Sizable;
  this.TransparencyKey = Color.Empty;
  this.Opacity = 1;

You are modifying properties that have a rather large impact on a form. TransparencyKey and FormBorderStyle require changing the window style bits. Windows doesn't allow those style bits to be changed. Windows Forms implements them by completely destroying the window and re-creating it from scratch. Neat trick, but that takes time and the form will be repainted each time you change the style. Causing the unpleasant visual effect you see.

Try this:
1. Set Opacity to 0 so the form becomes invisible
2. Change BackColor, no problem
3. Change FormBorderStyle, window gets recreated
4. Change TransparencyKey, window gets recreated
5. Change Opacity to 1, window gets recreated, then visible

For example:

  this.Opacity = 0;
  this.BackColor = Color.FromKnownColor(KnownColor.Control);
  this.FormBorderStyle = FormBorderStyle.Sizable;
  this.TransparencyKey = Color.Empty;
  this.Opacity = 1;
情绪失控 2024-07-21 09:49:36

如果所有这些都失败了,您可以通过阻止所有发送到表单的绘制消息来尝试一些低级黑客攻击。

警告:我并不提倡使用此方法,但如果您确实愿意,可以尝试一下。 它过去对我有帮助。

Win32.LockWindowUpdate(this.Handle);
try
{
   //make your changes here
}
finally
{
  //release the lock
  Win32.LockWindowUpdate((IntPtr)0);
}

该代码依赖于以下支持代码:

public class Win32
{
  private Win32() { }

    /// <summary>
    /// Lock ore relase the wndow for updating.
    /// </summary>
    [DllImport("user32")]
    public static extern int LockWindowUpdate(HWND hwnd);
 }

If all that fails, you could try some lowlevel hacking by blocking all paint messages to your form.

WARNING: I am not promoting the use of this method, but you can try it if you really want to. It has helped me in the past.

Win32.LockWindowUpdate(this.Handle);
try
{
   //make your changes here
}
finally
{
  //release the lock
  Win32.LockWindowUpdate((IntPtr)0);
}

This code relies on the following supporting code:

public class Win32
{
  private Win32() { }

    /// <summary>
    /// Lock ore relase the wndow for updating.
    /// </summary>
    [DllImport("user32")]
    public static extern int LockWindowUpdate(HWND hwnd);
 }
彻夜缠绵 2024-07-21 09:49:36

将表单的所有“图像”一次性发送到屏幕的一种方法是启用 DoubleBuffer。

在构造函数中,您可以设置 VB.NET 的 ControlStyles

SetStyle(ControlStyles.DoubleBuffer, True)

A way to send all the "image" of the form to the screen in one step is to enable DoubleBuffer.

In the Constructor you can set the ControlStyles

VB.NET:

SetStyle(ControlStyles.DoubleBuffer, True)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文