因为Tk不提供截图接口,winfo_rootx()/winfo_rooty()返回屏幕绝对坐标但受DPI缩放、多屏偏移、窗口装饰影响,需结合winfo_width()/winfo_height()计算真实区域后用ImageGrab.grab()截取。
tkinter 窗口截图为什么不能直接用
?
因为
本身不提供截图接口,
和
返回的是窗口左上角相对于屏幕的坐标,但实际渲染可能受 DPI 缩放、多显示器偏移、窗口装饰(标题栏/边框)影响——直接截屏容易切掉顶部或偏移一截。
必须手动算出真实窗口区域,再交给
截取。
和
是相对于父容器的坐标,**不能用**
要用
+
获取屏幕绝对位置
宽度/高度得用
和
,不是
解析出来的值(后者含初始尺寸,不反映 resize 后状态)
Windows 上开启“缩放与布局” > 125% 时,
默认按物理像素截,需额外处理缩放因子
怎么用 Pillow 正确截 tkinter 主窗口(含标题栏)
多数人想截的是用户看到的完整窗口(含标题栏、边框),这时候不能只截 client 区域。关键在:先获取窗口在屏幕上的完整矩形,再传给
。
示例代码片段:
立即学习
“
Python免费学习笔记(深入)
”;
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
下载
root.after(1000, capture_window) # 延迟确保窗口已映射
root.mainloop()
必须等窗口真正显示后再截图,否则
可能返回 -32000
Linux/macOS 下
可能失败,需改用
或 X11/Wayland 工具
macOS Catalina+ 需手动授权「屏幕录制」权限,否则返回黑图
只截客户区(去掉标题栏和边框)怎么做?
如果只要程序绘制的内容(比如 Canvas、Label 等控件区域),就得排除系统级装饰。Tkinter 没有直接 API 返回客户区内偏移,但可以通过对比
和
估算边框厚度——不推荐,误差大。
更稳的方式:让窗口无边框(
),自己画标题栏,或用
包裹内容区并单独截图。
用
解析出 "400x300+100+200" 中的宽高,再结合
计算客户区左上角 —— **不可靠,不同系统差异大**
稳妥做法:把要截图的内容放在一个
里,调用
等获取其屏幕坐标,再截
例如截图某个
:
保存图片时常见的路径和格式陷阱
看似简单,但路径错误、扩展名不匹配、中文路径、目录不存在都会静默失败或报错。
路径必须存在,
要提前加
扩展名决定格式:
→ PNG,
→ JPEG;写成
却传
会报错
Windows 下路径含中文一般没问题,但某些旧 Pillow 版本对
的 Unicode 路径支持弱,建议用
构造路径
避免用
或环境变量,如
,
不做 shell 展开
截图这事,最麻烦的从来不是调哪个函数,而是窗口坐标在不同系统、DPI、窗口状态下的微妙偏差。多显示器切换、Alt+Tab 切后台、甚至 PyCharm 调试器弹窗都可能让
返回临时无效值——真要稳定,得加重试或 visible 状态判断。
screenshot()Tkwinfo_rootx()winfo_rooty()PIL.ImageGrab.grab()root.winfo_x()root.winfo_y()root.winfo_rootx()root.winfo_rooty()root.winfo_width()root.winfo_height()geometry()ImageGrab.grab()ImageGrab.grab()
from tkinter import Tk
from PIL import ImageGrab
root = Tk()
root.title("测试窗口")
root.geometry("400x300")
def capture_window():
x = root.winfo_rootx()
y = root.winfo_rooty()
w = root.winfo_width()
h = root.winfo_height()
注意:winfo_height() 不包含标题栏高度,但 winfo_rootx/y 已定位到标题栏左上角
# 所以 grab((x, y, x+w, y+h)) 就是完整窗口(含标题栏)
img = ImageGrab.grab(bbox=(x, y, x+w, y+h))
img.save("window.png")winfo_rootx()ImageGrab.grab()pyautogui.screenshot()winfo_rootx()winfo_x()root.overrideredirect(True)Frameroot.winfo_geometry()root.winfo_rootx()Frameframe.winfo_rootx()Canvasc.winfo_rootx(), c.winfo_rooty(), c.winfo_width(), c.winfo_height()img.save()os.makedirs(os.path.dirname(path), exist_ok=True).png.jpg.pngformat="JPEG"save()pathlib.Path~"~/Desktop/cap.png"ImageGrabwinfo_rootx()