You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 09:25:31