如何让Tkinter程序等待<FocusOut>事件完成后再终止?
解决方案
要解决这个问题,核心是跟踪文本框内容是否发生变更,仅在内容修改过的情况下,才在窗口关闭时执行保存操作,同时确保保存完成后再退出程序。以下是修改后的完整代码:
import tkinter as tk import sqlite3 # 全局变量跟踪内容是否修改 is_modified = False def action(): """保存文本框内容到数据库,并重置修改标记""" global is_modified if not is_modified: return # 无修改则直接返回 txt_content = textbox.get("1.0", tk.END) # 使用参数化查询避免SQL注入风险 query = "UPDATE Test SET text = ? WHERE rowid = 1;" cursor = sqliteConnection.cursor() cursor.execute(query, (txt_content,)) sqliteConnection.commit() cursor.close() # 重置修改标记 is_modified = False # 重置文本框的修改状态(避免重复触发<<Modified>>) textbox.edit_modified(False) def on_text_modified(event): """文本框内容变更时设置修改标记""" global is_modified # 仅当文本框确实被修改时更新标记 if textbox.edit_modified(): is_modified = True def on_closing(): """窗口关闭前的处理逻辑""" # 检查是否有未保存的修改 if is_modified: action() # 关闭数据库连接 sqliteConnection.close() # 销毁窗口 root.destroy() # 数据库初始化 sqliteConnection = sqlite3.connect('DB.db') cursor = sqliteConnection.cursor() # 创建表 query = """ CREATE TABLE IF NOT EXISTS Test ( text TEXT ); """ cursor.execute(query) # 检查是否已有数据行,避免重复插入空行 cursor.execute("SELECT COUNT(*) FROM Test;") row_count = cursor.fetchone()[0] if row_count == 0: query = "INSERT INTO Test (text) VALUES('');" cursor.execute(query) sqliteConnection.commit() cursor.close() # 读取当前数据库中的内容,初始化文本框 cursor = sqliteConnection.cursor() cursor.execute("SELECT text FROM Test WHERE rowid = 1;") current_content = cursor.fetchone()[0] cursor.close() # GUI创建 root = tk.Tk() textbox = tk.Text(root) textbox.pack(side="top") # 设置初始内容 textbox.insert("1.0", current_content) # 绑定焦点失焦事件 textbox.bind("<FocusOut>", lambda e: action()) # 绑定内容修改事件,跟踪变更 textbox.bind("<<Modified>>", on_text_modified) # 设置窗口关闭协议 root.protocol("WM_DELETE_WINDOW", on_closing) root.mainloop()
关键修改说明
- 内容变更跟踪:通过
is_modified变量和Text组件的<<Modified>>虚拟事件,实时检测文本框内容是否被修改。每次内容变更时,on_text_modified会将is_modified设为True,保存后再重置为False。 - 优化SQL查询:替换原代码的f-string拼接SQL为参数化查询,彻底避免SQL注入风险,这是数据库操作的最佳实践。
- 窗口关闭处理:通过
root.protocol("WM_DELETE_WINDOW", on_closing)自定义关闭逻辑,先检查是否有未保存的修改,仅在需要时执行保存,完成后再关闭数据库连接并销毁窗口。 - 修复原代码的数据库连接问题:原代码初始化后关闭了数据库连接,导致后续保存操作报错。修改后保持连接直到窗口关闭时再关闭,确保操作正常执行。
- 避免重复插入空行:添加了行计数检查,仅在表为空时插入初始空行,防止多次运行程序时重复插入数据。
内容的提问来源于stack exchange,提问作者alfred
相关产品推荐
相关产品推荐

