我有Form以下属性:
Panel透明背景,和Dock = DockStyle.FillPictureBox用大Width和Height,显示滚动条现在所有控件都设置为DoubleBuffered,包括表单本身.一切都按预期工作,除了滚动PictureBox的面板时,表单背景图像滚动,它重复显示垂直和水平撕裂,虽然它的静态图像符合表单的大小,当你停止滚动它显示正确.这仅在拖动滚动条时发生,如果我单击滚动条中的任何一点来移动它,它会正确显示.
根据我的理解,Double Buffering应该消除这种情况,但即使使用双缓冲也是如此,可能稍微好一点,但滚动时仍然是一个巨大的问题.
我试图将所有控件放在另一个面板中,而不是使用表单背景图像,并将此面板放在窗体上,但它没有任何区别.
Han*_*ant 11
您正在与Windows系统选项进行战斗,名为"拖动时显示窗口内容".它为所有现代版本的Windows启用.关闭它不是一个现实的目标,因为它是一个系统选项,它会影响所有应用程序的所有窗口.没有后门有选择地绕过这个选项.
启用它后,操作系统会优化窗口的滚动.它执行快速bitblt以移动视频帧缓冲区中的像素,并仅为滚动显示的窗口部分生成绘制消息.向下滚动时,就像底部几行像素一样.底层的winapi调用是ScrollWindowEx().意图是为应用程序提供响应更快的UI,实现滚动所需的工作量要少得多.
您可以看到它的前进方向,ScrollWindowEx()也会移动由窗体的BackgroundImage绘制的像素.你可以看到.接下来你看到的是优化涂料的副作用,它只重绘了所显示的窗口部分.因此移动的背景图像像素不会重绘.看起来像"涂抹"效果.
有一个简单的解决方法,只需为面板的Scroll事件实现一个事件处理程序并调用Invalidate().所以整个面板再次重绘:
private void panel1_Scroll(object sender, ScrollEventArgs e) {
panel1.Invalidate();
}
Run Code Online (Sandbox Code Playgroud)
但现在你会注意到油漆的副作用不再被优化.你仍然看到像素被移动,然后透支.这有多可见取决于BackgroundImage的绘制成本.通常从不便宜,因为它没有最佳的像素格式(32bppPArgb),并且没有合适的尺寸,因此需要重新调整以适应窗口.视觉效果类似于"pogo",在面板的一个边缘上快速抖动.
您不太可能发现可接受或想要完成优化BackgroundImage的工作.阻止ScrollWindowEx()执行其工作需要一个非常大的武器,你可以调整LockWindowUpdate().像这样:
using System.Runtime.InteropServices;
...
private void panel1_Scroll(object sender, ScrollEventArgs e) {
if (e.Type == ScrollEventType.First) {
LockWindowUpdate(this.Handle);
}
else {
LockWindowUpdate(IntPtr.Zero);
panel1.Update();
if (e.Type != ScrollEventType.Last) LockWindowUpdate(this.Handle);
}
}
[DllImport("user32.dll", SetLastError = true)]
private static extern bool LockWindowUpdate(IntPtr hWnd);
Run Code Online (Sandbox Code Playgroud)
效果很好,背景图像像素现在稳定.任何其他像素,嗯,不是那么多.另一种视觉效果,让我们称之为"皱纹".通过将窗口置于合成模式可以完成摆脱该工件.哪个双缓冲整个窗口表面,包括子控件:
protected override CreateParams CreateParams {
get {
const int WS_EX_COMPOSITED = 0x02000000;
var cp = base.CreateParams;
cp.ExStyle |= WS_EX_COMPOSITED;
return cp;
}
}
Run Code Online (Sandbox Code Playgroud)
只有剩下的工件是这不是非常便宜的代码的副作用.滚动时,它可能看起来不那么平滑.否则会告诉你为什么28年前窗户被设计成不透明的.
| 归档时间: |
|
| 查看次数: |
1656 次 |
| 最近记录: |