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

调用window.quit()后Tk窗口无法关闭致程序崩溃问题求助

解决Tcl_AsyncDelete错误:CheckboxTreeview文件选择窗口崩溃问题

问题核心原因

点击按钮调用window.quit()退出事件循环后,Tk内部资源开始清理,但代码仍尝试访问tree.get_checked()获取选中项,导致Tcl异步处理上下文混乱,触发Tcl_AsyncDelete: async handler deleted by the wrong thread错误。该问题在Apple Silicon和Ubuntu的Tk实现中均存在。

修复方案1:调整Tk代码逻辑

关键是在窗口销毁前获取选中内容,避免事件循环退出后操作已失效的部件。修改后的代码如下:

def selectFiles(DictionaryOfFiles):
    from ttkwidgets import CheckboxTreeview
    import tkinter as tk
    from tkinter import ttk

    selected_items = []

    def on_select():
        nonlocal selected_items
        # 先获取选中项,再销毁窗口
        selected_items = tree.get_checked()
        window.destroy()

    window = tk.Tk()
    tree = CheckboxTreeview(window)
    tree.pack()
    window.title('Select files for analysis')
    window.geometry('400x400')

    key_lst = list(DictionaryOfFiles.keys())  
    val_lst = list(DictionaryOfFiles.values())
    for n in key_lst: 
        parent_id = tree.insert("", "end", n, text=n)
        child_id = tree.insert(n, "end", DictionaryOfFiles[n], text=DictionaryOfFiles[n])
        tree.change_state(parent_id, "checked")
        tree.change_state(child_id, "checked")

    exit_button = ttk.Button(window, text="Select files", command=on_select)
    exit_button.pack(pady=20)
    
    window.mainloop()  # 窗口销毁后自动退出循环

    selection_dict = {}
    for n in selected_items:
        # 跳过文件夹节点,只处理文件节点
        if n in val_lst:
            position = val_lst.index(n)
            selection_dict[key_lst[position]] = n

    return selection_dict

关键修改点

  • 新增on_select回调函数:点击按钮时先获取选中项并保存,再销毁窗口,确保部件处于有效状态时读取数据
  • 修复原代码中val_lst.index([n])的错误:val_lst元素为字符串,直接用val_lst.index(n),并过滤文件夹节点
  • 替换按钮命令为自定义回调,避免提前退出事件循环导致部件失效

修复方案2:使用PyQt适配Apple Silicon

如果不局限于Tk,推荐使用PyQt实现原生UI体验,其在Apple Silicon上兼容性更好,避免Tcl相关问题。示例代码如下:

from PyQt6.QtWidgets import (QApplication, QMainWindow, QTreeView, QPushButton, QVBoxLayout, QWidget,
                             QFileSystemModel)
from PyQt6.QtCore import Qt, QDir
import sys

def selectFiles(DictionaryOfFiles):
    app = QApplication(sys.argv)
    window = QMainWindow()
    central_widget = QWidget()
    layout = QVBoxLayout(central_widget)

    # 带复选框的文件系统模型
    model = QFileSystemModel()
    model.setRootPath(QDir.currentPath())
    model.setFilter(QDir.Filter.AllEntries | QDir.Filter.NoDotAndDotDot)

    tree_view = QTreeView()
    tree_view.setModel(model)
    tree_view.setRootIndex(model.index(QDir.currentPath()))
    tree_view.setSelectionMode(QTreeView.SelectionMode.ExtendedSelection)
    tree_view.setHeaderHidden(True)
    tree_view.setSelectionBehavior(QTreeView.SelectionBehavior.SelectRows)
    tree_view.expandAll()

    selected_files = []

    def on_select():
        nonlocal selected_files
        indexes = tree_view.selectedIndexes()
        selected_files = [model.filePath(idx) for idx in indexes if idx.column() == 0]
        window.close()

    btn = QPushButton("Select files")
    btn.clicked.connect(on_select)

    layout.addWidget(tree_view)
    layout.addWidget(btn)

    window.setCentralWidget(central_widget)
    window.setWindowTitle('Select files for analysis')
    window.resize(400, 400)
    window.show()

    app.exec()

    # 转换为目标字典格式
    selection_dict = {}
    key_lst = list(DictionaryOfFiles.keys())
    val_lst = list(DictionaryOfFiles.values())
    for path in selected_files:
        filename = path.split('/')[-1]
        if filename in val_lst:
            pos = val_lst.index(filename)
            selection_dict[key_lst[pos]] = filename

    return selection_dict

优势

  • 原生Mac UI风格,适配Apple Silicon芯片
  • 避免Tk的Tcl底层错误,稳定性更高
  • 提供更灵活的文件选择过滤和层级管理能力

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 17:24:58