Tkinter结合Pyttsx3执行后窗口自动关闭的原因及修复咨询
Tkinter窗口自动关闭问题排查与修复
问题描述
基于Tkinter和Pyttsx3开发的叫号系统,程序运行后窗口会自动关闭,无法保持打开状态持续输入内容并完成语音播报。
原因分析
- Pyttsx3与Tkinter主循环冲突:
pyttsx3的runAndWait()方法会在语音播报完成后尝试终止程序主线程的循环,和Tkinter的mainloop()产生冲突,直接导致窗口被强制关闭。 - 重复初始化引擎:每次点击“APPELER”按钮都重新初始化
pyttsx3.Engine,不仅浪费资源,还会加重循环冲突的概率。 - 冗余变量定义:原代码中
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
相关产品推荐
相关产品推荐

