调用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
相关产品推荐
相关产品推荐

