Python中如何等待带Tkinter GUI的函数返回用户输入值后执行后续代码
问题分析与解决方案
你的核心问题在于没搞明白Tkinter的事件驱动特性:普通函数调用不会阻塞等待用户交互,mark()函数在创建窗口后就直接执行到末尾返回了,根本没等到用户点击"Submit"按钮——这就是为什么obj1、obj2、obj3全是None。而且你后来尝试的按钮触发方式也没用,因为那些变量在mark()调用完成时就已经被赋值为None,后续用户操作根本改不了它们的值。
解决思路:用回调函数串联异步流程
Tkinter的交互是异步的,我们不能用「顺序调用→等待返回」的思路,而是要用回调函数把流程串起来:收集完第一个数据后,再触发第二个窗口,等第三个数据收集完成,最后再调用pdf_gen()。同时用类来管理状态,避免全局变量的混乱。
修正后的代码示例
import tkinter as tk from tkinter import StringVar, OptionMenu, Button, Label, Frame import random # 假设你已经定义了 cur(数据库游标)和 random_num_gen 函数 class QuestionPaperGenerator: def __init__(self): # 用来保存三个步骤的结果 self.collected_data = [] self.total_steps = 3 self.current_step = 0 def show_mark_window(self, diff, on_complete): """弹出选择窗口,收集数据后调用回调函数""" diff = diff.upper() win = tk.Tk() win.title("Question Paper Generator") win.configure(background='#ECECEC') win.geometry('650x500') t1 = StringVar(win) t1.set("THEORITICAL") def handle_submit(): question_type = t1.get() # 执行数据库查询 cur.execute(f"SELECT MAX(ID) FROM {diff}4{question_type}") max_id = cur.fetchone()[0] rand_id = random_num_gen(max_id)[0] # 取第一个随机ID(你原代码里j=0) cur.execute(f"SELECT QS FROM {diff}4{question_type} WHERE ID = {rand_id}") question = list(cur.fetchone()) win.destroy() # 关闭当前窗口 on_complete(question) # 把结果传给回调 # 界面元素 Label(win, font="SF\Mono 16 bold", text="Enter Question Type", background='#ECECEC', justify='left').grid(column=0, row=1, padx=20, pady=10) frame5 = Frame(win) frame5.grid(column=0, row=2, padx=0, pady=10) OptionMenu(frame5, t1, "THEORITICAL", "PROOF", "MCQ", "NUMERICAL").grid(column=0, row=0) frame4 = Frame(win) frame4.grid(column=0, row=11, padx=0, pady=10) Button(frame4, text="Submit", command=handle_submit).grid(column=0, row=0) win.mainloop() def on_step_complete(self, result): """每完成一个步骤的回调""" self.collected_data.append(result) self.current_step += 1 if self.current_step < self.total_steps: # 还没完成所有步骤,继续弹出下一个窗口 self.show_mark_window("Easy", self.on_step_complete) else: # 三个数据都收集完了,生成PDF self.pdf_gen(*self.collected_data) def pdf_gen(self, obj1, obj2, obj3): """你的PDF生成逻辑""" print("开始生成PDF,获取到的题目:") print(f"题目1: {obj1}") print(f"题目2: {obj2}") print(f"题目3: {obj3}") # 这里替换成你的实际PDF生成代码 def start(self): """启动整个流程""" self.show_mark_window("Easy", self.on_step_complete) # 运行程序 if __name__ == "__main__": app = QuestionPaperGenerator() app.start()
关键说明
- 用类管理状态:
collected_data列表保存每一步的结果,避免了全局变量的混乱,也方便在回调之间共享数据。 - 回调串联流程:
show_mark_window函数接受一个on_complete回调,用户点击提交后,会把结果传给这个回调,然后关闭当前窗口。 - 分步触发:每完成一个步骤,检查是否收集完所有数据,如果没有就继续弹出下一个选择窗口,直到三个数据都收集好,才调用
pdf_gen()。
这样就能保证程序严格等待用户完成每一步输入后,再执行后续的PDF生成逻辑。
内容的提问来源于stack exchange,提问作者tejas
相关产品推荐
相关产品推荐

