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

Tkinter结合Pyttsx3执行后窗口自动关闭的原因及修复咨询

Tkinter窗口自动关闭问题排查与修复

问题描述

基于Tkinter和Pyttsx3开发的叫号系统,程序运行后窗口会自动关闭,无法保持打开状态持续输入内容并完成语音播报。

原因分析

  1. Pyttsx3与Tkinter主循环冲突:pyttsx3的runAndWait()方法会在语音播报完成后尝试终止程序主线程的循环,和Tkinter的mainloop()产生冲突,直接导致窗口被强制关闭。
  2. 重复初始化引擎:每次点击“APPELER”按钮都重新初始化pyttsx3.Engine,不仅浪费资源,还会加重循环冲突的概率。
  3. 冗余变量定义:原代码中self.numero_box = tk.StringVar()之后被ttk.Entry实例覆盖,属于无效代码,虽不直接导致窗口关闭,但会造成代码冗余。

修复方法

1. 提前初始化语音引擎

在类的__init__方法中一次性完成语音引擎的初始化,避免每次播报重复创建实例:

def __init__(self):
    super().__init__()
    # ... 原有窗口初始化代码 ...
    # 初始化语音引擎
    self.engine = pyttsx3.init()
    self.voices = self.engine.getProperty("voices")
    self.engine.setProperty('rate', 170)
    self.engine.setProperty("voice", self.voices[3].id)

2. 用线程分离语音播报任务

导入threading模块,将语音播报放在子线程中执行,彻底避免阻塞Tkinter主循环:

# 先在顶部导入threading
import threading

def appel(self):
    Tosay = ('Le numéro ' + self.numero_box.get() + ' est appelé à la caisse')
    # 定义独立的播报函数
    def speak_task():
        self.engine.say(Tosay)
        self.engine.runAndWait()
    # 启动子线程执行播报,daemon=True确保线程随主程序退出
    threading.Thread(target=speak_task, daemon=True).start()
    
    print(Tosay)
    self.numero_box.delete(0, 'end')
    self.numero_box.focus()

3. 移除冗余代码

删除被覆盖的StringVar定义,精简代码:

# 删除这一行无用代码
# self.numero_box = tk.StringVar()

完整修复后代码

import tkinter as tk
from tkinter import ttk
import pyttsx3
import threading


class Call(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title('Calling System')
        self.geometry('500x300')
        self.resizable(False, False)

        self.numero_label = ttk.Label(self, text='Numéro Suivant :')
        self.numero_label.place(x=10, y=50)

        self.numero_box = ttk.Entry(self)
        self.numero_box.place(x=226, y=45)
        self.numero_box.focus()

        self.effacer = ttk.Button(self, text='EFFACER', command=self.efface)
        self.effacer.place(x=10, y=200)

        self.appeler = ttk.Button(self, text='APPELER', command=self.appel)
        self.appeler.place(x=365, y=200)

        self.quitter = ttk.Button(self, text='QUITTER', command=self.leave)
        self.quitter.place(x=365, y=250)

        # 初始化语音引擎
        self.engine = pyttsx3.init()
        self.voices = self.engine.getProperty("voices")
        self.engine.setProperty('rate', 170)
        self.engine.setProperty("voice", self.voices[3].id)

    def leave(self):
        self.quit()

    def efface(self):
        self.numero_box.delete(0, 'end')
        self.numero_box.focus()

    def appel(self):
        Tosay = ('Le numéro ' + self.numero_box.get() + ' est appelé à la caisse')
        def speak_task():
            self.engine.say(Tosay)
            self.engine.runAndWait()
        threading.Thread(target=speak_task, daemon=True).start()
        
        print(Tosay)
        self.numero_box.delete(0, 'end')
        self.numero_box.focus()

if __name__ == "__main__":
    app = Call()
    app.mainloop()

内容的提问来源于stack exchange,提问作者vintagechocolate

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 05:45:39