我正在创建一个小程序,它使用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: - )
答案 0 :(得分:0)
是什么让你认为它正在退出主循环?如果没有达到最终的打印语句,主循环不会“退出”,程序就会崩溃。根据您提供的证据,崩溃发生在方法engine.runAndWait()
中。
如果你的程序没有崩溃,你真正的意思是程序不再响应事件,那么唯一的解释是engine.runAndWait()
正在阻塞。为什么会发生这种情况我不知道,因为我从未使用过pyttsx,尽管runAndWait
的文档说它会阻塞直到所有排队的事件都被处理过。也许它认为队列中还有一些东西。
答案 1 :(得分:0)
我必须在pyttsx周围写一个线程安全的包装器。 pyttsx中的所有函数都需要进入同一个线程。
如果您正在使用 startLoop ,请注意不要让“完成 - 说话”#39;当命令队列为空时回调返回,或者您无法再次访问循环,但 startLoop 也不会返回。我认为我遇到了 runAndWait 的问题。
此外,从回调中调用 Engine.stop 似乎会使事情无法正常工作。 (但是你也不能从其他任何地方调用它。)永远不要输入说空字符串或非ascii字符。 (可能与平台有关)。
答案 2 :(得分:0)
我建议您使用pyttsx3。它更新得多,速度更快,并且总体上更易于编程。它使用的声音完全基于系统的文本到语音的api,例如Windows的sapi 5。