截屏时延迟 C# (WPF)

Posted

技术标签:

【中文标题】截屏时延迟 C# (WPF)【英文标题】:Delay while taking Screenshot of Desktop C# (WPF) 【发布时间】:2016-10-17 16:08:42 【问题描述】:

我正在做一些程序来截屏。它的功能与 Windows 的截图工具相同。用户通过在屏幕上绘制矩形来定义区域并拍摄。

我关注了这个惊人的tutorial,就像通过覆盖整个桌面来打开新窗口一样。然后我在 Window 上绘制矩形并在矩形内拍摄。如果鼠标移动正常,则截图正确。喜欢这张图片

但是,当鼠标移动得更快时,截图不正确,如下图所示。镜头从矩形区域中取出

这里是源代码:

public partial class CapturingArea : Window


    public  BitmapSource    mTakenScreenShot;
    private Point           mStartPoint;
    private Point           mEndPoint;                
    private Rectangle       mDrawRectangle;       

    public CapturingArea()
    
        InitializeComponent();
        InitMainWindow();            
        Mouse.OverrideCursor = Cursors.Cross;

        mStartPoint = new Point();
        mEndPoint   = new Point();            
          

    /*Close Window by pressing ESC Button*/
    private void Window_KeyUp(object sender, KeyEventArgs e)
    
        if (e.Key == Key.Escape)
        
            Mouse.OverrideCursor = Cursors.Arrow;
            this.Close();                
        
            

    /*When Mouse is clicked 
     get the current point of Mouse and Start Drawing Rectangle on the Canvas*/
    private void cnDrawingArea_MouseDown(object sender, MouseButtonEventArgs e)
                
        if(mDrawRectangle != null)
            this.cnDrawingArea.Children.Remove(mDrawRectangle);

        mStartPoint = e.GetPosition(this);                  

        mDrawRectangle = new Rectangle
        
            Stroke = Brushes.Red,
            StrokeThickness = 0.5
        ;

        Canvas.SetLeft(mDrawRectangle, mStartPoint.X);
        Canvas.SetTop(mDrawRectangle, mStartPoint.Y);
        this.cnDrawingArea.Children.Add(mDrawRectangle);
    

    /* Continue drawing Rectangle while Mouse is moving on the Canvas Area*/
    private void cnDrawingArea_MouseMove(object sender, MouseEventArgs e)
    
        if(e.LeftButton == MouseButtonState.Released)
        
            return;
        

        Point tmpPoint = e.GetPosition(this.cnDrawingArea);

        int xPos = (int) Math.Min(tmpPoint.X, mStartPoint.X);
        int yPos = (int) Math.Min(tmpPoint.Y, mStartPoint.Y);

        int recWidth = (int) Math.Max(tmpPoint.X, mStartPoint.X) - xPos;
        int recHeight = (int)Math.Max(tmpPoint.Y, mStartPoint.Y) - yPos;

        mDrawRectangle.Width = recWidth;
        mDrawRectangle.Height = recHeight;
        Canvas.SetLeft(mDrawRectangle, xPos);
        Canvas.SetTop(mDrawRectangle, yPos);
    
    /*Initialize Window to cover whole screen*/
    private void InitMainWindow()
    
        this.WindowStyle = WindowStyle.None;
        this.Title = string.Empty;
        this.ShowInTaskbar = false;
        this.AllowsTransparency = true;
        this.Background = new SolidColorBrush(Color.FromArgb(0x10, 0x10, 0x10, 0x10));
     //   this.Topmost = true;
        this.Left   = SystemParameters.VirtualScreenLeft;
        this.Top    = SystemParameters.VirtualScreenTop;
        this.Width  = SystemParameters.VirtualScreenWidth;
        this.Height = SystemParameters.VirtualScreenHeight;
    


    /*First calculate Starting Ending points according to 
     mouse move and take screenshot*/
    private void CaptureScreen(int X1, int Y1, int X2, int Y2)
    
        int StartXPosition = 0;
        int StartYPosition = 0;
        int tmpWidth = 0;
        int tmpHeight = 0;

        if (X1 < X2 && Y1 < Y2)          /*Drawing Left to Right*/
        
            StartXPosition = X1;
            StartYPosition = Y1;
            tmpWidth  = X2 - X1;
            tmpHeight = Y2 - Y1;
         
        else if(X1 > X2 && Y1 < Y2)     /*Drawing Top to Down*/
        
            StartXPosition = X2;
            StartYPosition = Y1;
            tmpWidth  = X1 - X2;
            tmpHeight = Y2 - Y1;
         
        else if(X1 > X2 && Y1 > Y2)     /*Drawing Down to Top*/
        
            StartXPosition = X2;
            StartYPosition = Y2;
            tmpWidth = X1 - X2;
            tmpHeight = Y1 - Y2;
         
        else if(X1 < X2 && Y1 >Y2)      /*Drawing Right to Left */
        
            StartXPosition = X1;
            StartYPosition = Y2;
            tmpWidth  = X2 - X1;
            tmpHeight = Y1 - Y2;
        
        StartXPosition += 2;
        StartYPosition += 2;
        tmpWidth -= 2;
        tmpHeight -= 2;
        mTakenScreenShot = ScreenCapture.CaptureRegion(StartXPosition, StartYPosition, tmpWidth, tmpHeight, false);
        Mouse.OverrideCursor = Cursors.Arrow;
    

    /*get the screenshot and by calculating real positions of Desktop*/
    private void cnDrawingArea_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
                
            if (e.LeftButton == MouseButtonState.Released)
            
                mEndPoint = e.GetPosition(this.cnDrawingArea);

                if (mDrawRectangle != null)
                    this.cnDrawingArea.Children.Remove(mDrawRectangle);

                Point StartDesktopPosition = this.PointToScreen(mStartPoint);   
                Point EndDesktopPosition = this.PointToScreen(mEndPoint);

                int tempX1 = (int)StartDesktopPosition.X;
                int tempY1 = (int)StartDesktopPosition.Y;
                int tempX2 = (int)EndDesktopPosition.X;
                int tempY2 = (int)EndDesktopPosition.Y;

                CaptureScreen(tempX1, tempY1, tempX2, tempY2);
                this.DialogResult = true;
                this.Close();
            
        
    

鼠标快速移动右截屏时有什么解决办法或建议吗?

谢谢。

【问题讨论】:

【参考方案1】:

当鼠标移动得非常快时,Windows 会将鼠标移动聚合到一条消息中,以免使用大量 WM_MOUSEMOVE 使任何程序过载。您可以通过Mouse.GetIntermediatePoints 获取 WPF 中这些中间点的列表。

我怀疑你的问题是鼠标在最后一次移动和左键向上之间在屏幕上快速移动,你错过了一大堆中间点。

尝试将此作为实验,同时在左按钮向上处理程序中绘制矩形。我相信这将使矩形与屏幕截图区域相匹配。如果您随后检查中间点,您可能会看到一堆移动数据排队。

要解决这个问题,为什么不直接使用最后一次鼠标移动作为 mEndPoint 而不是在左按钮向上处理程序中调用 GetPosition?这应该会给你正确的行为,因为它会完全反映你当前绘制矩形的方法。然后,无论中间移动如何,您都将捕获矩形坐标本身,而不是由左键向上位置形成的新矩形。

【讨论】:

按照您的建议,我在左按钮向上处理程序中绘制矩形并启动计时器(延迟 100 毫秒)。当定时器计时,获取矩形的坐标、高度和宽度,然后捕获矩形区域,同时停止定时器。

以上是关于截屏时延迟 C# (WPF)的主要内容,如果未能解决你的问题,请参考以下文章

Android 4.0 ,如何截屏,当竖屏时。

Winform C#截屏实现

Winform C#截屏实现

Winform C#截屏实现

Winform C#截屏实现

Android 模拟器在截屏时一直退出