0

我正在创建一个小程序,只是为了好玩,它可以打开程序并执行类似的操作。

我正在做一个维基百科搜索,程序会读出来,我希望 MessageBoxW 将文本写到屏幕上。

我希望这两件事同时发生,因为现在它首先显示消息框,然后在我关闭窗口之后它正在阅读文本

def Mbox(title, text, style):
    return ctypes.windll.user32.MessageBoxW(0, text, title, style)

def Mbox(title, text, style):
    return ctypes.windll.user32.MessageBoxW(0, text, title, style)


def wikipediaSearch():
    global user_input

    user_input = user_input.replace("search", '')
    result = wikipedia.summary(user_input, sentences=2)

    raw_text = result
    convert_text = unicodedata.normalize('NFKD', raw_text).encode('ascii', 'ignore')
    convert_text = convert_text.decode('utf-8')
    new_text = re.sub(r'\(.*\)', '', convert_text)
    print(new_text)

    Mbox(user_input, new_text, 0)

    voice.say(new_text)
    voice.runAndWait()
4

1 回答 1

2

pyttsx创建一个在单独线程中运行的辅助类:

import threading
import pyttsx

class Say(object):
    """Function-like class to speak using pyttsx."""
    _thread = None

    def __init__(self, message):
        if not isinstance(message, str):
            raise ValueError("message is not a string")
        if Say._thread is not None:
            Say._thread.join()
            Say._thread = None
        Say._thread = threading.Thread(target=self._worker,
                                       name="Say",
                                       args=(message,))
        Say._thread.start()

    def _worker(self, message):
        engine = pyttsx.init()
        engine.say(message)
        engine.runAndWait()

def WaitAllSaid():
    if Say._thread is not None:
        Say._thread.join()
        Say._thread = None

因为 pyttsx 的行为就像一个单例,并且任何时候只有一个 pyttsx 实例可以在同一个 Python 进程中说话,所以我将全局变量封装到Say类中,并让实例构造函数等待任何现有的话语完成,然后开始一个新的pyttsx 发言的线程。

本质上,Say(message)等待任何正在进行的话语完成,然后开始说出新的声音,然后返回。它不会等待消息完全说完才返回;它在消息开始时立即返回。

WaitAllSaid()等待任何正在进行的话语,然后收获工作线程。如果要修改 pyttsx 引擎或语音属性,请先调用WaitAllSaid()以确保当时没有话语正在进行中。否则可怜的 pyttsx 可能会感到困惑。

OP 函数的最后四行wikipediaSearch现在变成了类似

    print(new_text)

    Say(new_text)
    Mbox(user_input, new_text, 0)
    WaitAllSaid()

如果 pyttsx 已经在说话,则Say()阻塞,直到所有先前的消息都已经说完。当指定的消息开始播放时,它立即返回。

直到所有所说的WaitAllSaid()都被说出为止。你可以从函数中省略它,只要你确保在 Python 程序退出之前调用它。wikipediaSearch()WaitAllSaid()

在不完全传统的设计上:至少在 Linux 上,如果尝试将相同的 pyttsx 对象用于单独的语句,则 pyttsx 会出现问题。让帮助线程创建实例效果更好。在 Linux 上测试,这种模式是全局变量和各种形式的单例类中最健壮的一种。我根本不使用 Windows,所以我无法对其进行测试,唉。

于 2019-01-13T00:50:18.067 回答