Python две вещи одновременно с потоками - PullRequest
0 голосов
/ 11 января 2019

Я создаю небольшую программу, просто для удовольствия, которая открывает программы и делает подобные вещи.

Я выполняю поиск в Википедии, и программа зачитывает его, и я хочу, чтобы текст выписывался на экран с помощью 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()

1 Ответ

0 голосов
/ 13 января 2019

Создайте вспомогательный класс, который запускает 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 ведет себя как singleton , и только один экземпляр 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() просто блокирует до тех пор, пока все сказанное не будет произнесено. Вы можете опустить его из функции wikipediaSearch(), если убедитесь, что WaitAllSaid() вызывается до выхода из программы Python.

В не совсем традиционном дизайне: по крайней мере, в Linux у pyttsx есть проблемы, если кто-то пытается использовать один и тот же объект pyttsx для отдельных операторов. Наличие вспомогательного потока для создания экземпляра работает намного лучше. При тестировании на Linux этот шаблон был наиболее устойчивым среди глобальных переменных и различных форм одноэлементных классов. Я вообще не пользуюсь Windows, поэтому не могу на ней протестировать, увы.

...