【问题标题】:PrintScreen only active windowPrintScreen 仅活动窗口
【发布时间】:2011-01-14 15:07:27
【问题描述】:

我正在编写一个简单的 Windows 窗体实用程序来截取整个屏幕或活动窗口并保存文件。 winform 有一个名为“Capture”的按钮,单击该按钮会截取屏幕截图。

我的代码完全适用于整个屏幕,但无法为活动窗口弄清楚。

根据我当前的代码,如果我选择“活动窗口”,它最终会打印筛选应用程序本身,这不是我想要的。

这是我的代码(在 Capture_Click 方法下):

try
        {
            this.Hide();

            bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
            //bmpScreenshot = new Bitmap(this.Bounds.Width, this.Bounds.Height, PixelFormat.Format32bppArgb);

            gfxScreenshot = Graphics.FromImage(bmpScreenshot);

            if (AltPrint.Checked)
            {
                gfxScreenshot.CopyFromScreen(this.Bounds.X, this.Bounds.Y, 0, 0, this.Bounds.Size, CopyPixelOperation.SourceCopy);
            }
            else
            {
                gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
            }

            bmpScreenshot.Save(SaveLocation, ImageFormat.Png);

            number++;
        }

【问题讨论】:

  • 你在重建PrintScreenAlt+PrintScreenkeypresses吗?
  • select active window 到底是什么意思?你是怎么选的?
  • @Austin:不,我的 winform 有一个名为 Capture 的按钮。点击它,截图。上面粘贴的代码在button_Click方法中。
  • @rmx:通过单击窗口标题栏进行选择。我确实意识到,一旦我在我的 winform 上单击“捕获”,之前的窗口就不再被选中,所以我正在寻找一种可能的解决方法。
  • xbonez 请参阅我的回答,了解如何做到这一点。您需要了解一些关于 p/invoke 的知识。

标签: c# winforms


【解决方案1】:

在您的button_Click 方法中,要捕获一个不是正在捕获的窗口,我能看到的唯一可能的方法是使用user32 Windows API。

您首先需要平台调用一些这样的方法:

[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, GetWindowLongNIndex nIndex);

我推荐www.pinvoke.net/ 了解更多信息。

这是我自己的Window 课程(正在进行中,但可用),欢迎您使用它作为示例:http://pastebin.com/fj2tEaPY

其中一些对您有用的属性是:

  • 获取AllWindows
  • 获取TaskbarWindows
  • 设置ForegroundWindow

您需要获取当前窗口的句柄(使用 get ForegroundWindow,然后使用 Handle 属性),然后找到要捕获图像的窗口,可能使用类似于TaskbarWindows。一旦你有了窗口,你需要发送按键Alt + PrtScn (可能再次使用user32 API,但我不会进入它。)然后使用静态ForegroundWindow属性来设置使用您在开始时保存的句柄作为前景的原始窗口。

祝你好运!

【讨论】:

    【解决方案2】:

    据我所知,您的代码使用其自身形式的边界来捕获“活动”窗口。这可能不是你想要的。

    如果您想使用鼠标“打印”一个窗口(而不是可能更容易实现的热键),您需要能够从您自己的表单让用户指向另一个窗口进行捕获。这是一个描述如何做到这一点的想法:

    1. 当用户按下“捕获”按钮时,捕获鼠标并启动拖动操作。
    2. 让用户将鼠标(可能现在有“靶心”或“相机”光标)拖动到窗口以进行捕捉。
    3. 当用户释放鼠标时,确定它位于顶部的窗口,并使用该窗口的位置和大小来捕捉正确的像素。

    您可能需要使用 P/Invoke 来获取有关桌面上所有顶级窗口的信息。

    请注意,“鼠标捕获”与“屏幕捕获”非常不同。当应用程序“捕获鼠标”时,它会获得鼠标光标的所有权,并且即使鼠标移出应用程序窗口的边界,也无法跟踪鼠标。

    【讨论】:

    • 我有另一个想法。请参阅对 OP 的评论。
    • 我会接受这个答案,因为您允许拖动和选择的想法让我想到了我当前的解决方案。
    【解决方案3】:

    您的 cmets 似乎明白,一旦您的应用获得焦点(当您单击它时),其他应用就会失去焦点并且不再“活跃”。

    一种可能的替代方法:您的应用程序在获得焦点时会收到WM_SETFOCUS 消息。该消息的 wParam 是刚刚放弃焦点的任何窗口的句柄 - 并且该窗口属于您要捕获的应用程序。

    当然,该窗口只是一个子窗口或控件,但您可以确定哪个应用拥有该按钮。

    【讨论】:

      【解决方案4】:

      我最终选择了不同的路线。

      我允许用户调整我的表单窗口的大小以准确覆盖他们需要截屏的区域,然后当他们单击按钮时,表单会自行隐藏,对它所覆盖的区域进行截屏并再次出现。与我最初的计划相反,我相信这会更有益,因为我的目标用户(我所在的超频论坛的朋友)很少只截取一个窗口的屏幕截图。他们大多需要覆盖几个窗口(温度监控、时钟速度监控、稳定性测试等)。

      感谢所有回答的家伙。他们肯定让我思考,让我意识到我的选择是什么。

      如果其他人需要它,这是我用于仅捕获部分屏幕的按钮的代码:

              try
              {
                  this.Hide();
                  Thread.Sleep(250);
      
                  bmpScreenshot = new Bitmap(this.Bounds.Width, this.Bounds.Height, PixelFormat.Format32bppArgb);
      
                  gfxScreenshot = Graphics.FromImage(bmpScreenshot);
      
                  gfxScreenshot.CopyFromScreen(this.Bounds.X, this.Bounds.Y, 0, 0, this.Bounds.Size, CopyPixelOperation.SourceCopy);
      
                  bmpScreenshot.Save(SaveLocation, ImageFormat.Png);
      
                  tbxStatus.AppendText(Environment.NewLine);
                  tbxStatus.AppendText(Environment.NewLine);
                  tbxStatus.AppendText("Screenshot saved at " + SaveLocation);
      
                  numSuffix++;
              }
              catch (Exception ex)
              {
                  tbxStatus.AppendText(Environment.NewLine);
                  tbxStatus.AppendText(Environment.NewLine);
                  tbxStatus.AppendText("Unable to take screenshot. Exception: " + ex.ToString());
              }
              finally
              {
                  this.Show();
              }
      

      【讨论】:

        【解决方案5】:

        需要借鉴市售截屏应用的设计,比如Psp。我认为您需要使用“热”键来触发活动窗口的捕获。而不是在 Capture_Click 事件上执行此操作。这样,您可以隐藏应用程序的窗口,使其不会成为活动窗口。然后当用户按下“热”键时,您就可以捕获它。

        【讨论】:

          【解决方案6】:

          SendKeys 呢?

          Windows.Forms.SendKeys.Send("%{PRTSC}");
          

          它将当前选定的窗口复制到剪贴板对象。

          比打电话

          BitmapSource image = Clipboard.GetImage();
          

          你可以恢复你的图像

          【讨论】:

          • 但是“当前选中的窗口”是他自己的应用程序。
          • 但这让我回到了同样的问题。如果我告诉我的应用发送 Alt_printscreen,按键会截取我的表单。
          猜你喜欢
          • 2020-09-02
          • 2011-02-03
          • 2014-10-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多