你如何截取 Tkinter 中特定小部件的屏幕截图?

How do you take a screenshot of a particular widget in Tkinter?

如何截取特定小部件的屏幕截图?搜索时,我不断收到“如何截取整个屏幕的屏幕截图”或“如何截取 window 的屏幕截图”,但我想知道如何准确截取一个小部件(一个框架)的屏幕截图。恐怕这个论坛会要求我给他们一个代码片段,而实际上我不知道该怎么做。所以我只是问这是否可能,以及如何去做。

PS:如果可以只给一个函数 widget 变量,然后它会去搜索那个 widget 然后截取它的精确屏幕截图,我将非常感激。我知道有 pyautogui 可以搜索图像,我只是不知道我到底需要做什么,因为这个框架不是图像,它总是不时地变化,所以自动化可能会混淆。

也许你可以获取该帧的坐标,然后根据该坐标截屏。这应该有效

PS: I would really appreciate if it is possible to just give a function the widget variable, and then it would go searching for that widget and then take a precise screenshot of it.

不,没有可以截取小部件屏幕截图的功能。你可以做的是使用 PIL 来截取图像。为此,您需要框架的坐标,您可以使用小部件的方法动态获取它。

首先你需要安装PIL,所以:

pip install Pillow 

如果在 Linux 上,则 PIL.ImageGrab 将不起作用,因此请安装另一个用于截屏的库,而不是 PIL:

pip install pyscreenshot

这是一个模块化代码,您可以通过将小部件作为参数传递给函数来与任何小部件一起使用:

from PIL import ImageGrab # If on Linux, use `import pyscreenshot as ImageGrab` after installing it 

def capture(wid,file_name='img',file_format='png'):
    """Take screenshot of the passed widget"""

    x0 = wid.winfo_rootx()
    y0 = wid.winfo_rooty()
    x1 = x0 + wid.winfo_width()
    y1 = y0 + wid.winfo_height()
    
    im = ImageGrab.grab(bbox=(x0, y0, x1, y1)) # bbox means boundingbox, which is shown in the image below
    im.save(f'{file_name}.{file_format}')  # Can also say im.show() to display it

现在您只需将此功能实现到您的代码中,这是一个示例:

from tkinter import *
from PIL import ImageGrab # If on Linux, use `import pyscreenshot as ImageGrab` after installing it

root = Tk()

def capture(wid,file_name='img',file_format='png'):
    """Take screenshot of the passed widget"""

    x0 = wid.winfo_rootx()
    y0 = wid.winfo_rooty()
    x1 = x0 + wid.winfo_width()
    y1 = y0 + wid.winfo_height()

    im = ImageGrab.grab((x0, y0, x1, y1))
    im.save(f'{file_name}.{file_format}')  # Can also say im.show() to display it

frame = Frame(root,bg='red',width=100,height=185)
frame.pack()
frame.pack_propagate(0) # Make it not auto-resize according to widgets

for i in range(5):
    Button(frame,text=f'Button {i}').pack()

Button(root,text='Take screenshot',command=lambda: capture(frame,img_name='frame',img_format='png')).pack()

root.mainloop()

如果您想知道传入 bbox 的坐标指的是什么,那么: