桌面屏幕叠加 – 新forms的闪烁问题

作为我的开源DeskPins 克隆的一部分 (两个单独的链接,一个用于原始,一个用于GitHub上的克隆),我需要允许用户与桌面交互。 我认为最简单的方法是打开一个新表单并在其上绘制桌面内容。 然后我应该能够轻松设置鼠标光标并为用户提供关于当前焦点的窗口的视觉提示。

更复杂的替代方法是使用p / invoke到SetSystemCursor并在其他窗口的WM_PAINT事件队列中注入自定义代码(以及可能的其他WinApi相关工作,例如,如果我的程序exception终止,则游标清理将是一个问题)。 我不想这样做。

我下面的代码正在工作,唯一的问题是屏幕闪烁 。 设置DoubleBuffered = true后,它变得更好(而不是屏幕闪烁,它变成了父窗体闪烁 ),但仍然很明显。 所以现在每次打开叠加表单时我的表单都会闪烁。

我能做些什么来使它平稳过渡,就好像新窗口没有打开一样? 有一个“冻结”效果是可以的=任何动画都会被暂停。

 public sealed partial class DesktopOverlayForm : Form { public DesktopOverlayForm() { InitializeComponent(); //make full screen //http://stackoverflow.com/a/2176683/897326 Rectangle bounds = Screen.AllScreens .Select(x => x.Bounds) .Aggregate(Rectangle.Union); this.Bounds = bounds; //set desktop overlay image this.BackgroundImage = MakeScreenshot(); } ///  /// Based on this answer on StackOverflow: /// http://stackoverflow.com/questions/1163761/capture-screenshot-of-active-window ///  private static Bitmap MakeScreenshot() { Rectangle bounds = Screen.GetBounds(Point.Empty); Bitmap image = new Bitmap(bounds.Width, bounds.Height); using (Graphics g = Graphics.FromImage(image)) { g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size); } return image; } private void DesktopOverlayForm_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Escape) { this.Close(); } } } 

DoubleBuffered需要DoubleBuffered模式。 父表单闪烁的原因是因为在绘制覆盖表单之前激活覆盖表单(因此父表单被停用并且需要在视觉上指示该表单)。

为了解决这个问题,需要在不激活的情况下显示覆盖forms,然后在第一次绘制后立即激活覆盖forms。 第一个是通过覆盖一个很少知道的虚拟保护属性Form.ShowWithoutActivation ,第二个是通过挂钩到OnPaint方法和一个表单级别标志来实现的。 像这样的东西

 public sealed partial class DesktopOverlayForm : Form { public DesktopOverlayForm() { // ... this.DoubleBuffered = true; } protected override bool ShowWithoutActivation { get { return true; } } bool activated; protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); if (!activated) { activated = true; BeginInvoke(new Action(Activate)); } } } 

我过去曾对我闪烁的Form这样做过。 对于我的情况,双缓冲区并没有真正起作用。

 //this.DoubleBuffered = true; //doesn't work protected override CreateParams CreateParams { //Very important to cancel flickering effect!! get { CreateParams cp = base.CreateParams; cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED //cp.Style &= ~0x02000000; // Turn off WS_CLIPCHILDREN not a good idea when combined with above. Not tested alone return cp; } } 

我们的想法是替换CreateParams参数。 另见:

  • Winforms双缓冲