1

我有以下代码来拖动表单并在拖动时使其透明。问题是它闪烁并且不平滑拖动。我在表格上有一张照片,不知道是不是这个原因。我怎样才能让它不闪烁。如果我删除不透明度,那么它会被快速/平滑地拖动。

[DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, 
    int lParam);
[DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();

public void Drag(MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        this.Opacity = 0.9;
        ReleaseCapture();

        SendMessage(Handle, 0xA1, 0x2, 0);
        this.Opacity = 1;
    }
}

private void Body_MouseDown(object sender, MouseEventArgs e)
{       
    Drag(e);
}
4

1 回答 1

3

Form 和 Control 类有许多“重”属性,需要对底层的原生 Windows 窗口进行大量更改。它们是与传递给本机 CreateWindowEx() 调用的样式标志相关联的属性。Opacity 属性以及 TransparencyKey 属性就是这样,当您将它们从默认值更改时,窗口需要另一个样式标志 WS_EX_LAYERED。

这是一个问题,因为在创建窗口时指定了这个样式标志。Windows 支持在使用 SetWindowsLongPtr() 创建窗口后更改它们,但这总是参差不齐。特别是对于 WS_EX_LAYERED,当它打开时,很多事情都会发生在幕后。它是通过利用视频适配器中称为“层”的硬件功能来实现的。层是一个单独的视频内存块,其像素与主内存结合在一起。支持提供不透明效果(乘法)和透明键效果(省略)的混合器。

因此,在创建窗口后即时更改 Opacity 属性是相当困难的。以至于 WPF 完全禁止它。但是 Winforms 没有,它需要处理 Windows 98 的限制。这也使得更改 ShowInTaskbar、RightToLeft、FormBorderStyle 等属性变得困难。它使用一个技巧来允许更改这些属性,它完全破坏了本机窗口并重新创建它,现在使用新的样式标志。

问题解决了,但这确实有明显的副作用。不可避免地,您看到的窗口消失了,新窗口被创建并绘制在同一个位置。这会导致您抱怨的闪烁。此外,破坏窗口会导致大量内部状态丢失。Winforms 尽最大努力恢复该状态以及为新窗口恢复该状态,但“我目前正在移动”状态无法恢复。模态移动循环已终止。

这个问题的解决方法是粗略但简单的。将“属性”窗口中的“不透明度”属性设置为 99%。并更改您的代码以将其恢复为 99 而不是 100。现在样式位永远不必更改,因此您将不再获得这些工件。

于 2013-01-08T18:52:10.383 回答