首页 > 解决方案 > 完成某事后如何关闭消息框

问题描述

按下按钮时,播放 mp3 文件,并出现一个消息框,说明播放中。消息框中有一个停止mp3文件的按钮,我想在mp3文件结束时关闭消息框而不按该按钮。

在播放音乐之前,由于各种任务,播放窗口出现需要一些时间。所以,我改变了代码的顺序,这样当按下按钮时,首先出现一个窗口,剩下的工作就完成了。但是,在消息框因“msg.exec_()”而关闭之前不会启动下一个任务。我很困惑该怎么做。

任何帮助将不胜感激。

def play(self):
    file = open("op.txt", "r").read().replace("\n", " ")
    tts = gTTS(text = str(file),lang='ko',slow = False)
    tts.save("op.mp3")
    file = open("./button/b1/b1.txt", "r").read().replace("\n", " ")
    tts = gTTS(text = str(file),lang='ko',slow = False)
    tts.save("voice.mp3")
    file = open("./button/b1/b1-1.txt", "r").read().replace("\n", " ")
    tts = gTTS(text = str(file),lang='ko',slow = False)
    tts.save("voice2.mp3")
    
    sound1 = AudioSegment.from_file("./op.mp3", format="mp3")
    sound2 = AudioSegment.from_file("./voice.mp3", format="mp3")
    sound3 = AudioSegment.from_file("./voice2.mp3", format="mp3")
    combined = sound1 + sound2 + sound3

    file_handle = combined.export("./complite.mp3", format="mp3")

    pygame.init()
    pygame.mixer.music.load('./complite.mp3')
    pygame.mixer.music.play(0)
    if not pygame.mixer.music.get_busy():
        self.msg.close()
        
    self.msg.setIcon(QMessageBox.Information)
    self.msg.setWindowTitle('Playing')
    self.msg.setText('playing...')
    self.msg.setStandardButtons(QMessageBox.Cancel)
    retval = self.msg.exec_()
    
    if retval == QMessageBox.Cancel :
        pygame.mixer.music.stop()

标签: pythonpyqt5

解决方案


您应该使用 QMediaPlayer 而不是使用 pygame 播放音频,因为它允许更轻松地处理 Qt,因为除了使用 Qt 事件循环之外,它还有指示播放状态的信号。

另一方面,您必须在辅助线程中执行文本到语音的过程,以免阻塞 GUI,也不需要生成中间文件,因为您可以重现字节。

import io
import sys
import threading
from functools import cached_property

from PyQt5.QtCore import pyqtSignal, QBuffer, QIODevice, QObject
from PyQt5.QtWidgets import QApplication, QMessageBox, QPushButton, QVBoxLayout, QWidget
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer

from gtts import gTTS
from pydub import AudioSegment


class Translator(QObject):
    started = pyqtSignal()
    finished = pyqtSignal()
    translated = pyqtSignal(bytes)

    def translate(self, *, texts, language):
        threading.Thread(
            target=self._translate, args=(texts, language), daemon=True
        ).start()

    def _translate(self, texts, language):
        self.started.emit()
        sounds = []
        for text in texts:
            tts = gTTS(text=text, lang=language, slow=False)
            fp = io.BytesIO()
            tts.write_to_fp(fp)
            fp.seek(0)
            sounds.append(AudioSegment.from_mp3(fp))
        combined = sum(sounds)
        fp = io.BytesIO()
        combined.export(fp, format="wav")
        self.translated.emit(fp.getvalue())
        self.finished.emit()


class Widget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        lay = QVBoxLayout(self)
        lay.addWidget(self.button)

        self.button.clicked.connect(self.handle_button_clicked)
        self.translator.translated.connect(self.handle_translate_translated)
        self.player.stateChanged.connect(self.handle_player_state_changed)
        self.messagebox.finished.connect(self.handle_messagebox_finished)

    @cached_property
    def button(self):
        return QPushButton("Start")

    @cached_property
    def translator(self):
        return Translator()

    @cached_property
    def player(self):
        return QMediaPlayer()

    @cached_property
    def buffer(self):
        return QBuffer()

    @cached_property
    def messagebox(self):
        messagebox = QMessageBox()
        messagebox.setIcon(QMessageBox.Information)
        messagebox.setWindowTitle("Playing")
        messagebox.setText("playing...")
        messagebox.setStandardButtons(QMessageBox.Cancel)
        return messagebox

    def handle_button_clicked(self):
        texts = self.load_texts()
        self.button.setEnabled(False)
        self.translator.translate(texts=texts, language="ko")

    def handle_translate_translated(self, data):
        self.buffer.close()
        self.buffer.setData(data)
        self.buffer.open(QIODevice.ReadOnly)

        self.player.setMedia(QMediaContent(), self.buffer)
        self.player.play()
        self.messagebox.open()

    def handle_player_state_changed(self, state):
        if state == QMediaPlayer.StoppedState:
            self.messagebox.close()
            self.button.setEnabled(True)

    def handle_messagebox_finished(self):
        self.player.stop()

    def load_texts(self):
        texts = []
        for filename in ("op.txt", "./button/b1/b1.txt", "./button/b1/b1-1.txt"):
            with open(filename, "r") as f:
                text = f.read().replace("\n", " ")
                texts.append(text)
        return texts


if __name__ == "__main__":
    app = QApplication(sys.argv)

    widget = Widget()
    widget.show()

    sys.exit(app.exec_())

推荐阅读