8

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

我将背景颜色从 Lime 更改为默认值 我将 FormBorderStyle 更改为 FixedSingle 我将 TransparencyKey 更改为 Colour.None

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

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

G

4

5 回答 5

9

新答案:覆盖 WndProc 并在应用新的 Window 属性时阻止 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);
        }
    }
于 2009-03-05T17:39:54.427 回答
4

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

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

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

于 2009-03-05T17:39:29.777 回答
4

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

试试这个: 1. 将 Opacity 设置为 0,使窗体不可见 2. 更改 BackColor,没问题 3. 更改 FormBorderStyle,重新创建窗口 4. 更改 TransparencyKey,重新创建窗口 5. 将 Opacity 更改为 1,重新创建窗口,然后可见

例如:

  this.Opacity = 0;
  this.BackColor = Color.FromKnownColor(KnownColor.Control);
  this.FormBorderStyle = FormBorderStyle.Sizable;
  this.TransparencyKey = Color.Empty;
  this.Opacity = 1;
于 2009-03-06T03:52:38.227 回答
3

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

警告:我不提倡使用这种方法,但如果你真的想尝试,你可以试试。它过去曾帮助过我。

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);
 }
于 2010-01-12T09:02:06.937 回答
0

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

在构造函数中,您可以设置 ControlStyles

VB.NET:

SetStyle(ControlStyles.DoubleBuffer, True)
于 2009-03-05T17:42:24.763 回答