如何实现Tkinter GUI事件触发时导入执行Python模块及相关问题排查
解决方案
问题1:所有按钮点击都执行最后一个模块
原因
这是Python闭包的延迟绑定特性导致的:你在循环中给command传的lambda: OpenApp(app)不会在定义时捕获当前app的值,只会在按钮点击触发时才查找app变量的值,此时循环已经执行完毕,app自然就是列表最后一个元素的值。
修复方法
给lambda添加默认参数,在定义lambda时就把当前迭代的app值绑定进去:
# 把原来的command=lambda: OpenApp(app)改成 command=lambda app=app: OpenApp(app)
问题2:导入模块后无法开展后续交互
原因
有两个常见诱因:
importlib.import_module()只会执行模块的顶层代码一次,如果你子模块的交互逻辑写在if __name__ == "__main__"判断块里,导入时这个判断不成立,逻辑根本不会执行;- 子模块的阻塞式交互逻辑(比如
input()、循环监听)会和Tkinter的主线程事件循环冲突,要么卡住Tkinter界面,要么子模块逻辑被中断。
修复方法
优先选择用subprocess开独立进程运行子Python文件,比导入模块的兼容性更好,独立进程有自己的控制台窗口,交互不会和主Tkinter程序冲突:
首先要把Applications列表里的文件名处理成带完整路径的格式,然后修改OpenApp函数:
import sys import subprocess # 先修正Applications列表,过滤py文件,同时把文件夹加入导入路径(如果坚持用导入方式的话) sys.path.append('C:/Users/****/PycharmProjects/Gui Test') Applications = [filename.removesuffix('.py') for filename in os.listdir('C:/Users/****/PycharmProjects/Gui Test') if isfile(filename) and filename.endswith('.py')] # 改用subprocess的OpenApp示例 def OpenApp(app_path): # app_path是完整的py文件路径 subprocess.Popen([sys.executable, app_path], creationflags=subprocess.CREATE_NEW_CONSOLE)
修正后的完整代码参考
import os import tkinter as tk import sys import subprocess from os.path import isfile # 配置工作路径 WORK_DIR = 'C:/Users/****/PycharmProjects/Gui Test' sys.path.append(WORK_DIR) # 过滤得到所有py文件的完整路径 Applications = [os.path.join(WORK_DIR, filename) for filename in os.listdir(WORK_DIR) if isfile(os.path.join(WORK_DIR, filename)) and filename.endswith('.py')] def OpenApp(app_path): # 开新控制台运行子程序,互不干扰 subprocess.Popen([sys.executable, app_path], creationflags=subprocess.CREATE_NEW_CONSOLE) def App_Buttons(_root): i = 0 for app in Applications: # 提取文件名显示在按钮上 app_name = os.path.basename(app) tk.Button(_root, height=2, relief='solid', borderwidth=1, text=app_name, # 绑定当前app的值 command=lambda app=app: OpenApp(app), font=("Century Gothic", 16), ).grid(row=4 + i, column=0, padx=20, pady=15) tk.Label(_root, text=f'This is the description of App Name: {app_name}', font=("Century Gothic", 16) ).grid(row=4 + i, column=1, sticky='w') i += 1
内容的提问来源于stack exchange,提问作者Nathan Ngqwebo
相关产品推荐
相关产品推荐

