用pyttsx讲话后,Tkinter mainloop意外退出

时间:2011-12-27 13:13:37

标签: python tkinter text-to-speech

我正在创建一个小程序,它使用tkinter和pyttsx与用户进行交互。由于某种原因,脚本在说“按钮点击”后退出,而它应该留在主循环中。更奇怪的是,它甚至没有通过我在主循环下面添加的“检查点”。

以下是产生错误的代码的简化版本:

import Tkinter as tk
import pyttsx

def button_click():
    engine.say('button clicked')
    engine.runAndWait()

engine = pyttsx.init()

root = tk.Tk()
gameframe = tk.Frame(root)
gameframe.pack()
readybutton = tk.Button(gameframe, text = 'click', command = button_click)
readybutton.pack()

root.mainloop()

print('checkpoint')

如何解决这个问题?

更新: 通过谷歌我发现一些迹象表明这个问题可能与使用事件循环的tkinter和pyttsx以及Apple的Foundation和/或ObjC模块如何处理事件有关。由于我是Python的新手,我不太了解,但有些人可能会看到http://comments.gmane.org/gmane.comp.python.pyobjc.devel/5965

我还发现了一个几乎太简单,特定于mac的解决方法,它避免了完全使用pyttsx:

import os

phrase = 'button clicked'
os.system("/usr/bin/say " + phrase)

这也适用于tkinter: - )

3 个答案:

答案 0 :(得分:0)

是什么让你认为它正在退出主循环?如果没有达到最终的打印语句,主循环不会“退出”,程序就会崩溃。根据您提供的证据,崩溃发生在方法engine.runAndWait()中。

如果你的程序没有崩溃,你真正的意思是程序不再响应事件,那么唯一的解释是engine.runAndWait()正在阻塞。为什么会发生这种情况我不知道,因为我从未使用过pyttsx,尽管runAndWait的文档说它会阻塞直到所有排队的事件都被处理过。也许它认为队列中还有一些东西。

答案 1 :(得分:0)

当你从不同的线程调用它的Engine方法时,即使它们从未在时间上重叠,pyttsx也会崩溃。 (不仅仅是 runAndWait ,还有之类的东西。) startLoop runAndWait 阻止。

我必须在pyttsx周围写一个线程安全的包装器。 pyttsx中的所有函数都需要进入同一个线程。

如果您正在使用 startLoop ,请注意不要让“完成 - 说话”#39;当命令队列为空时回调返回,或者您无法再次访问循环,但 startLoop 也不会返回。我认为我遇到了 runAndWait 的问题。

此外,从回调中调用 Engine.stop 似乎会使事情无法正常工作。 (但是你也不能从其他任何地方调用它。)永远不要输入空字符串或非ascii字符。 (可能与平台有关)。

答案 2 :(得分:0)

我建议您使用pyttsx3。它更新得多,速度更快,并且总体上更易于编程。它使用的声音完全基于系统的文本到语音的api,例如Windows的sapi 5。