桌面屏幕叠加 - 新形式的闪烁问题 [英] Desktop screen overlay - new form flicker issue

查看:241
本文介绍了桌面屏幕叠加 - 新形式的闪烁问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于我的开源 DeskPins 克隆(两个独立的环节,一个是原来的,一个是在GitHub上克隆),我需要让用户与桌面交互。我想最简单的方法是在它的上面打开一个新的形式和油漆的桌面内容。然后,我应该能够轻松设置鼠标光标,并给予视觉线索用户关于当前处于焦点的窗口。



一个更复杂的替代方法是使用P / Invoke来SetSystemCursor而在其他窗口的WM_PAINT事件队列注射自定义代码(和潜在的其他WINAPI相关的工作,例如,光标清洗将是一个问题,如果我的程序异常终止)。我不希望走这条路。



我有以下工作的代码,唯一的问题是,屏幕闪烁。 DoubleBuffered = 它得到了更好的后,我将真(而不是屏幕闪烁成为父窗体闪烁),但仍显。所以现在我的形式闪烁每一个覆盖形式被打开的时间。



时有什么我可以做,使之成为流畅过渡,即仿佛一个新窗口没开?它没关系有一个冻结效应=任何动画将暂停

 公共密封部分类DesktopOverlayForm:表
{
公共DesktopOverlayForm()
{
的InitializeComponent();

//使全屏
//http://stackoverflow.com/a/2176683/897326
矩形范围= Screen.AllScreens
。选择(X = GT; x.Bounds)
.Aggregate(Rectangle.Union);
this.Bounds =界限;

//设置桌面叠加图像
this.BackgroundImage = MakeScreenshot();
}

///<&言论GT;
///基于这个答案在计算器上:
/// http://stackoverflow.com/questions/1163761/capture-screenshot-of-active-window
///< ; /备注>
私有静态位图MakeScreenshot()
{
矩形范围= Screen.GetBounds(Point.Empty);
位图图像=新位图(bounds.Width,bounds.Height);使用

(图形G = Graphics.FromImage(图片))
{
g.CopyFromScreen(Point.Empty,Point.Empty,bounds.Size);
}

返回图像;
}

私人无效DesktopOverlayForm_KeyDown(对象发件人,发送KeyEventArgs E)
{
如果(e.KeyCode == Keys.Escape)
{
this.Close();
}
}
}


解决方案

<是需要肯定code> DoubleBuffered 模式。其原因父窗体闪烁是因为叠加的形式被激活(这样父窗体被关闭,需要在视觉上表示)被画的覆盖形式之前。



为了解决这一中,覆盖形式需要显示而不被活化,然后只在第一涂料之后被激活。首先是通过覆盖一个鲜为人知的虚拟财产保护 Form.ShowWithoutActivation 实现,而第二挂接到的OnPaint 方法和一个表单级别标志。事情是这样的。



 公共密封部分类DesktopOverlayForm:表
{
公共DesktopOverlayForm()
{
// ...
this.DoubleBuffered = TRUE;
}

保护覆盖布尔ShowWithoutActivation {获得{返回true; }}

布尔激活;

保护覆盖无效的OnPaint(PaintEventArgs的E)
{
base.OnPaint(E);
如果(!激活)
{
激活= TRUE;
的BeginInvoke(新动作(激活));
}
}
}


As part of my open source DeskPins clone (two separate links, one for original, one for clone on GitHub), I need to allow user to interact with desktop. I figured the easiest way would be opening a new form and paint desktop contents on top of it. Then I should be able to easily set mouse cursor and give visual cues to user about windows that is currently in focus.

A more complicated alternative would be using p/invoke to SetSystemCursor and injecting custom code in other window's WM_PAINT event queue (and potentially other WinApi related work, for example, cursor cleaning would be an issue, if my program terminates abnormally). I'd prefer not to go this way.

The code I have below is working, the only issue is screen flicker. It got better after I set DoubleBuffered = true (instead of screen flicker it became parent form flicker), but still noticeable. So right now my form flickers every time an overlay form is opened.

Is there anything I can do to make it a smooth transition, i.e. as if a new window did not open? It's okay to have a "freeze" effect = any animation would be suspended.

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();
  }

  /// <remarks>
  ///  Based on this answer on StackOverflow:
  ///  http://stackoverflow.com/questions/1163761/capture-screenshot-of-active-window
  /// </remarks>
  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 mode is needed for sure. The reason for parent form flicker is because the overlay form is activated (thus the parent form is deactivated and need to visually indicate that) before the overlay form is painted.

In order to resolve that, the overlay form needs to be shown without being activated, and then to be activated just after the first paint. The first is achieved by overriding a rarely known virtual protected property Form.ShowWithoutActivation, and the second by hooking into OnPaint method and a form level flag. Something like this

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));
        }
    }
}

这篇关于桌面屏幕叠加 - 新形式的闪烁问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆