【问题标题】:(C++/Python) Capture window screenshot without caret indicator(C++/Python) 捕获不带插入符号的窗口截图
【发布时间】:2021-07-27 16:58:42
【问题描述】:

我想通过 Python 截取现有运行窗口的屏幕截图。
以下是我捕获记事本窗口的示例代码:

import time
import win32gui
import win32ui
import win32con
import pyautogui


def getWindowScreenshot(hwnd, output_file):
    r = win32gui.GetWindowRect(hwnd)
    width = r[2] - r[0]
    height = r[3] - r[1]
    wDC = win32gui.GetWindowDC(hwnd)
    dcObj = win32ui.CreateDCFromHandle(wDC)
    cDC = dcObj.CreateCompatibleDC()
    dataBitMap = win32ui.CreateBitmap()
    dataBitMap.CreateCompatibleBitmap(dcObj, width, height)
    cDC.SelectObject(dataBitMap)
    cDC.BitBlt((0, 0), (width, height), dcObj, (0, 0), win32con.SRCCOPY)

    # save the bitmap to a file
    dataBitMap.SaveBitmapFile(cDC, output_file)

    dcObj.DeleteDC()
    cDC.DeleteDC()
    win32gui.ReleaseDC(hwnd, wDC)
    win32gui.DeleteObject(dataBitMap.GetHandle())


# Press the green button in the gutter to run the script.
if __name__ == '__main__':

    window_title = "Untitled - Notepad"
    winHandle = win32gui.FindWindow(None, window_title)
    if winHandle == 0:
        raise RuntimeError(f"Window '{window_title}' is not opening!")

    # Bring the window to foreground in case it is overlap by other windows
    win32gui.SetForegroundWindow(winHandle)
    # Do something with Notepad
    time.sleep(3)

    # Capture the window
    getWindowScreenshot(winHandle, "output.bmp")

但是,有时捕获的图像会在输入文本框上显示闪烁的插入符号指示符。
我的问题是,如何在不获取插入符号的情况下捕获屏幕截图?


我已经尝试了一些解决方案,但不适合:

解决方案 1:

# Bring the window to foreground in case it is overlap by other windows
    win32gui.SetForegroundWindow(winHandle)
    # Do something with Notepad
    time.sleep(3)

    # Make the "Desktop window" focus
    win32gui.SetForegroundWindow(win32gui.GetDesktopWindow())

    # Capture the window
    getWindowScreenshot(winHandle, "output.bmp")

在截屏之前,尝试将“桌面”设置为前景窗口。
但是,win32gui.SetForegroundWindow(win32gui.GetDesktopWindow()) 命令会报错:

pywintypes.error: (0, 'SetForegroundWindow', 'No error message is available')

解决方案 2:

win32gui.SetForegroundWindow(win32gui.GetDesktopWindow()) 替换为win32gui.ShowWindow(winHandle, 4),其中4SW_SHOWNOACTIVATE。 代码运行正常,但记事本窗口在执行后没有失去焦点。

解决方案 3:

# Bring the window to foreground in case it is overlap by other windows
    win32gui.SetForegroundWindow(winHandle)
    # Do something with Notepad
    time.sleep(3)

    # Click outside of window
    r = win32gui.GetWindowRect(winHandle)
    pyautogui.click(r[2]+1, r[3]+1)

    # Capture the window
    getWindowScreenshot(winHandle, "output.bmp")

使用此解决方案,我尝试在记事本窗口外单击(单击桌面)。此代码似乎有效,但如果另一个窗口位于记事本窗口后面,则不会工作,如下所示:

执行代码时,它将单击 Windows 资源管理器窗口。所以,代码可以执行意外点击(例如:意外删除系统文件?)。

解决方案 4 (来自@SongZhu-MSFT)

if __name__ == '__main__':

    window_title = "Untitled - Notepad"
    winHandle = win32gui.FindWindow(None, window_title)
    if winHandle == 0:
        raise RuntimeError(f"Window '{window_title}' is not opening!")

    # Bring the window to foreground in case it is overlap by other windows
    win32gui.SetForegroundWindow(winHandle)
    # Do something with Notepad
    time.sleep(3)

    win32gui.EnableWindow(winHandle,False)
    # Capture the window
    getWindowScreenshot(winHandle, "output.bmp")
    time.sleep(0.5)
    getWindowScreenshot(winHandle, "output1.bmp")
    time.sleep(5)
    win32gui.EnableWindow(winHandle,True)

当我运行代码时,我仍然看到插入符号一直显示。 并且output.bmp + output1.bmp 仍然存在一个带有插入符号的图像。

系统信息:

  • Windows 10 1909
  • Python 3.7.9

【问题讨论】:

  • 我相信正确的术语是“焦点”;也许你可以使用win32gui.SetFocus(0) 或类似的东西?
  • @anatolyg,我试过win32gui.SetFocus(0),但还是不行。记事本窗口仍处于焦点位置。
  • HideCaret,然后调用ShowCaret
  • 我测试了代码,点击窗口时似乎出现了插入符号。也许你可以使用win32gui.EnableWindow(winHandle,False) 并在捕获结束后调用win32gui.EnableWindow(winHandle,True)
  • 睡前尝试拨打EnableWindow,如:win32gui.SetForegroundWindow(winHandle) win32gui.EnableWindow(winHandle,False) time.sleep(3)

标签: python c++ winapi window


【解决方案1】:

经过我的测试,我可以使用SendMessageW 发送WM_KILLFOCUS 使插入符号消失。

这是对我有用的代码:

import time
import win32gui
import win32ui
import win32con
import pyautogui
from ctypes import windll

def getWindowScreenshot(hwnd, output_file):
    r = win32gui.GetWindowRect(hwnd)
    width = r[2] - r[0]
    height = r[3] - r[1]
    wDC = win32gui.GetWindowDC(hwnd)
    dcObj = win32ui.CreateDCFromHandle(wDC)
    cDC = dcObj.CreateCompatibleDC()
    dataBitMap = win32ui.CreateBitmap()
    dataBitMap.CreateCompatibleBitmap(dcObj, width, height)
    cDC.SelectObject(dataBitMap)
    cDC.BitBlt((0, 0), (width, height), dcObj, (0, 0), win32con.SRCCOPY)

    # save the bitmap to a file
    dataBitMap.SaveBitmapFile(cDC, output_file)

    dcObj.DeleteDC()
    cDC.DeleteDC()
    win32gui.ReleaseDC(hwnd, wDC)
    win32gui.DeleteObject(dataBitMap.GetHandle())


if __name__ == '__main__':

    window_title = "Untitled - Notepad"
    winHandle = win32gui.FindWindow(None, window_title)
    if winHandle == 0:
        raise RuntimeError(f"Window '{window_title}' is not opening!")

    # Bring the window to foreground in case it is overlap by other windows
    win32gui.SetForegroundWindow(winHandle)
    # Do something with Notepad
    windll.user32.SendMessageW(winHandle, win32con.WM_KILLFOCUS, None, None)
    # Capture the window
    getWindowScreenshot(winHandle, "output.bmp")
    time.sleep(0.5)
    getWindowScreenshot(winHandle, "output1.bmp")

【讨论】:

  • SendMessageW (WM_KILLFOCUS) 也为我工作。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-22
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 2012-01-04
相关资源
最近更新 更多