python - 完成某事后如何关闭消息框
问题描述
按下按钮时,播放 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()
解决方案
您应该使用 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_())
推荐阅读
- openpyxl - 使用 Openpyxl 将列表的内容写入 Excel
- javascript - 如何最小化汉堡菜单的 JavaScript?
- jquery - 无法使用 jquery 获取 datalist 中的数组数据
- python - 如何处理 DataFrame 中的配对数据集?
- android - Android SQLite 数据库可以在应用程序外编辑吗?
- python - 使用 imap_tools 阅读后将电子邮件标记为未读
- stripe-payments - 将信息传递给 Stripe
- java - Android Retrofit RecyclerView 错误:不兼容的类型:
> 无法转换为回调 - c - 什么是 C 中的字符串表?
- bash - 在 n 次匹配后可靠地停止 bash 查找