<p>GUI通过<code>app.exec_()</code>实现了一个主循环,该循环用于执行诸如检查事件、信号、调用某些函数等任务。因此,如果我们中断循环,我们可以得到与您观察到的类似的意外行为。在您的例子中,<code>sleep()</code>是一个不应该使用的阻塞函数,Qt提供了它的替代方法,其中之一是使用<code>QEventLoop</code>和<code>QTimer</code>:</p>
<pre><code>def doGenerate(setValue):
for x2 in range(SIZE):
loop = QEventLoop()
QTimer.singleShot(1000, loop.quit)
loop.exec_()
setValue(x2 + 1)
print('Done')
</code></pre>
<p>如果不想显示“取消”按钮,则必须传递“无”:</p>
^{pr2}$
<p>如果您想使用<code>gTTS</code>,您必须通过线程来实现它,Qt提供了几种实现它的方法,在本例中,我将使用<code>QThreadPool</code>和{<cd7>}。我们将使用<code>QMetaObject.invokeMethod</code>来更新GUI的值,因为Qt禁止从非主线程的另一个线程更新GUI。在</p>
<pre><code>import sys, time
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from gtts import gTTS
class GTTSRunnable(QRunnable):
def __init__(self, data, progress):
QRunnable.__init__(self)
self.data = data
self.w = progress
def run(self):
for i, val in enumerate(self.data):
text, filename = val
tts = gTTS(text=text, lang='en')
tts.save(filename)
QMetaObject.invokeMethod(self.w, "setValue",
Qt.QueuedConnection, Q_ARG(int, i+1))
QThread.msleep(10)
class MainMenu(QMainWindow):
def __init__(self):
super().__init__()
self.genAudioButton = QPushButton('Generate', self)
self.genAudioButton.clicked.connect(self.generate)
self.setCentralWidget(self.genAudioButton)
self.show()
def generate(self):
try:
info = [("hello", "1.mp4"), ("how are you?", "2.mp4"), ("StackOverFlow", "3.mp4")]
self.progress = QProgressDialog('Work in progress', '', 0, len(info), self)
self.progress.setWindowTitle("Generating files...")
self.progress.setWindowModality(Qt.WindowModal)
self.progress.show()
self.progress.setValue(0)
self.doGenerate(info)
except Exception as e:
errBox = QMessageBox()
errBox.setWindowTitle('Error')
errBox.setText('Error: ' + str(e))
errBox.addButton(QMessageBox.Ok)
errBox.exec()
return
def doGenerate(self, data):
self.runnable = GTTSRunnable(data, self.progress)
QThreadPool.globalInstance().start(self.runnable)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainMenu()
ret = app.exec_()
sys.exit(ret)
</code></pre>