You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu下Python Tkinter关闭Toplevel后MSS截图报错XDefaultRootWindow()失败

环境信息

  • Ubuntu v22.04
  • MSS v7.0.1
  • Python 3.10

此问题与Stack Overflow上一个未解决的同类问题完全一致,可参考其最小复现示例。


项目功能说明

我开发了一个通过Python GUI控制游戏自动化脚本/宏的项目,使用流程如下:

  1. 运行程序,打开可导航的单页GUI。
  2. 选择要自动化的游戏。
  3. 选择要运行的脚本。
  4. 配置脚本选项(需通过Tkinter打开新的Toplevel窗口)。
  5. 点击Play按钮运行脚本。
  6. 系统逻辑:点击Play后,程序会对游戏客户端截图以定位窗口及各类UI元素位置,该操作在win.initialize()函数中执行。
  7. 可选操作:用户可暂停、恢复、停止脚本,或即时切换至其他脚本。

问题描述

问题出现在步骤4与步骤6之间。奇怪的是,第一次打开选项菜单、选择并保存选项后关闭弹窗,脚本可正常运行——MSS截图游戏客户端无报错;即使停止并重启脚本(无需重新配置选项),仍可正常工作。但如果再次打开弹窗修改选项,MSS尝试截图时会抛出如下错误:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.10/tkinter/__init__.py", line 1921, in __call__
    return self.func(*args)
  File "/home/my_project/env/lib/python3.10/site-packages/customtkinter/widgets/ctk_button.py", line 372, in clicked
    self.command()
  File "/home/my_project/src/view/info_frame.py", line 139, in play_btn_clicked
    self.controller.play_pause()
  File "/home/my_project/src/controller/bot_controller.py", line 21, in play_pause
    self.model.play_pause()
  File "/home/my_project/src/model/bot.py", line 103, in play_pause
    if not self.__initialize_window():
  File "/home/my_project/src/model/bot.py", line 132, in __initialize_window
    self.win.initialize()
  File "/home/my_project/src/model/runelite_bot.py", line 47, in initialize
    if not super().initialize():
  File "/home/my_project/src/utilities/window.py", line 128, in initialize
    a = self.__locate_minimap(client_rect)
  File "/home/my_project/src/utilities/window.py", line 257, in __locate_minimap
    if m := imsearch.search_img_in_rect(imsearch.BOT_IMAGES.joinpath("minimap.png"), client_rect):
  File "/home/my_project/src/utilities/imagesearch.py", line 52, in search_img_in_rect
    im = rect.screenshot()
  File "/home/my_project/src/utilities/geometry.py", line 64, in screenshot
    with mss.mss() as sct:
  File "/home/my_project/env/lib/python3.10/site-packages/mss/factory.py", line 34, in mss
    return linux.MSS(**kwargs)
  File "/home/my_project/env/lib/python3.10/site-packages/mss/linux.py", line 297, in __init__
    self.root = self.xlib.XDefaultRootWindow(self._get_display(display))
  File "/home/my_project/env/lib/python3.10/site-packages/mss/linux.py", line 184, in validate
    raise ScreenShotError(f"{func.__name__}() failed", details=details)
mss.exception.ScreenShotError: XDefaultRootWindow() failed

Screenshot error: XDefaultRootWindow() failed, {'retval': <mss.linux.LP_XWindowAttributes object at 0x7f31d8d38ac0>, 
    'args': (<mss.linux.LP_Display object at 0x7f31d8d38740>,)}

这表明问题与打开和关闭Tk Toplevel弹窗组件有关。 我确认用户关闭弹窗或点击save按钮时,Toplevel组件已被正确销毁,但无法理解为何第一次配置选项时可正常运行,再次修改后就报错。

可能的原因与解决方法

  1. Tkinter干扰X11显示资源
    Linux环境下,Toplevel窗口的创建/销毁可能意外修改了MSS依赖的X11显示连接。解决方法:初始化MSS时显式指定显示设备:

    import os
    # 替换原有with mss.mss() as sct:
    with mss.mss(display=os.environ.get("DISPLAY", ":0")) as sct:
    
  2. Toplevel销毁残留资源
    即使调用destroy(),Toplevel可能仍有未释放的X11资源。解决方法:关闭弹窗时强制刷新事件循环并解除引用:

    def close_options_window(toplevel):
        toplevel.destroy()
        toplevel.update_idletasks()  # 强制刷新事件循环
        toplevel = None  # 显式解除引用
    
  3. MSS实例重复创建冲突
    每次截图都新建MSS实例可能导致资源占用冲突。解决方法:全局复用一个MSS实例:

    # 项目初始化时创建全局实例
    global_sct = mss.mss()
    
    # 截图时直接调用全局实例
    def take_screenshot(rect):
        return global_sct.grab(rect)
    
  4. X11访问权限变动
    再次打开弹窗后程序可能失去X11根窗口访问权限。临时测试方案:启动程序前执行xhost +local:放宽本地权限(正式环境需配置合规权限)。


内容的提问来源于stack exchange,提问作者ktom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 15:30:54