PySimpleGUI点击Connect后Quit按钮无法响应的问题求助
问题解决:PySimpleGUI中Connect按钮触发循环导致Quit失效
你的核心问题是主线程被Connect按钮内的while True循环阻塞,无法回到主事件循环处理Quit按钮或窗口关闭事件。解决思路是用多线程把耗时的数据库循环操作从主线程剥离,让主线程专注处理GUI交互。
修改后的完整代码
import PySimpleGUI as sg import pyodbc import time import threading # 全局标志:控制数据库检查线程的启停 stop_thread = False def run_sql_check(server_name, db_name, username, password): global stop_thread trys = 0 while not stop_thread: trys += 1 print(f"This is try {trys}!") print("Connection establishment is starting...") # 捕获数据库连接异常,避免程序崩溃 try: conn = pyodbc.connect( 'DRIVER={ODBC Driver 17 for SQL Server};' f'SERVER={server_name};' f'DATABASE={db_name};' f'UID={username};' f'PWD={password}' ) time.sleep(0.5) print("The connection was established successfully!") cursor = conn.cursor() time.sleep(0.5) print("Data write in is starting...") # 创建test_users表 try: cursor.execute('''CREATE TABLE test_users (id INT PRIMARY KEY NOT NULL, name VARCHAR(255) NOT NULL, age INT NOT NULL);''') time.sleep(0.5) print("Table test_users created successfully!") # 插入数据 for i in range(5): cursor.execute(f"INSERT INTO test_users (id, name, age) VALUES ({i}, 'user{i}', {10 + i})") except: time.sleep(0.5) print("Table test_users already exists!") # 创建test_items表 try: cursor.execute('''CREATE TABLE test_items (id INT PRIMARY KEY NOT NULL, name VARCHAR(255) NOT NULL, price REAL NOT NULL);''') time.sleep(0.5) print("Table test_items created successfully!") # 插入数据 for i in range(5): cursor.execute(f"INSERT INTO test_items (id, name, price) VALUES ({i}, 'item{i}', {100 + i})") except: time.sleep(0.5) print("Table test_items already exists!") # 提交并关闭连接 conn.commit() conn.close() time.sleep(0.5) print("Connection was closed successfully!") # 再次连接并删除表 time.sleep(0.5) print("Connection establishment is starting...") conn = pyodbc.connect( 'DRIVER={ODBC Driver 17 for SQL Server};' f'SERVER={server_name};' f'DATABASE={db_name};' f'UID={username};' f'PWD={password}' ) time.sleep(0.5) print("The connection was established successfully!") cursor = conn.cursor() time.sleep(0.5) print("Data dropping is starting...") # 删除test_users表 try: cursor.execute('''DROP TABLE test_users;''') time.sleep(0.5) print("Table test_users dropped successfully!") except: time.sleep(0.5) print("Table test_users doesn't exist!") # 删除test_items表 try: cursor.execute('''DROP TABLE test_items;''') time.sleep(0.5) print("Table test_items dropped successfully!") # 修复原代码的拼写错误 except: time.sleep(0.5) print("Table test_items doesn't exist!") time.sleep(1) conn.commit() conn.close() time.sleep(0.5) print("The connection was closed successfully!") time.sleep(1) except Exception as e: time.sleep(0.5) print(f"The connection attempt wasn't successful. Error: {str(e)}") time.sleep(1) sg.theme('DarkBlue') layout = [ [sg.Text('Welcome to the SQL Availability Checker.')], [sg.Text('Please insert the name of the Database Server')], [sg.Input(key='server_name')], [sg.Text('Please insert the name of the Database')], [sg.Input(key='db_name')], [sg.Text('Please insert the name of the Username to connect to the database')], [sg.Input(key='Username')], [sg.Text('Please insert the password for the Username to connect to the database')], [sg.Input(key='password', password_char='*')], # 密码框隐藏输入 [sg.Button('Connect'), sg.Button('Quit')] , [sg.Text(text="Output")], [sg.Multiline(size=(60,15), font='Courier 8', expand_x=True, expand_y=True, write_only=True, reroute_stdout=True, reroute_stderr=True, echo_stdout_stderr=True, autoscroll=True, auto_refresh=True)] ] window = sg.Window('SQL Availability Checker', layout) while True: event, values = window.read() if event == sg.WIN_CLOSED or event == 'Quit': stop_thread = True # 设置停止标志,让子线程退出循环 break if event == 'Connect': stop_thread = False # 重置停止标志 server_name = values['server_name'] db_name = values['db_name'] username = values['Username'] password = values['password'] # 启动数据库检查线程,daemon=True表示主线程退出时自动终止子线程 threading.Thread(target=run_sql_check, args=(server_name, db_name, username, password), daemon=True).start() window.close()
关键改动说明
- 引入线程模块:添加
import threading,用多线程分离GUI和业务逻辑,避免主线程被阻塞。 - 全局停止标志:定义
stop_thread变量,用来控制子线程的循环启停。点击Quit时设为True,子线程会在下一次循环开始前退出。 - 封装业务逻辑:把原Connect按钮内的循环代码封装成
run_sql_check函数,作为子线程的执行目标。 - 异常捕获:给数据库连接和操作添加
try-except,避免连接失败导致程序崩溃。 - 线程启动方式:点击Connect时,启动子线程并设置
daemon=True,确保主线程退出时子线程自动结束,避免残留进程。 - 细节优化:
- 密码框添加
password_char='*'隐藏输入内容 - 修复原代码中删除test_items表时的打印错误(原打印成test_users)
- 用f-string替代字符串拼接,代码更简洁易读
- 密码框添加
内容的提问来源于stack exchange,提问作者Wandi
相关产品推荐
相关产品推荐

