Я работаю над примером приложения в Python, следуя архитектуре MVC с PyQT5 в качестве моего пользовательского интерфейса. В этом примере приложения у меня есть таймер обратного отсчета, который запускается в потоке и обновляет индикатор выполнения, пока поток активен. Тем не менее, на полпути через таймер обратного отсчета я хочу отобразить окно сообщения sh, но проблема в том, что окно сообщения не появится, если я вызову его из потока, поэтому программа зависает на неопределенное время. Я вставил код для приложения ниже. Как лучше справиться с этим и отправить информацию о потоке в исходный поток, чтобы я мог отобразить окно сообщения?
import sys
import time
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget
from PyQt5.QtWidgets import QGridLayout, QLineEdit, QPushButton, QVBoxLayout, QProgressBar, QMessageBox
from PyQt5.QtCore import Qt
import threading
class ExampleGUI(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('Sample Application')
# Set some main window's properties
self.setFixedSize(235, 235)
# Set the central widget and the general layout
self.generalLayout = QVBoxLayout()
self._centralWidget = QWidget(self)
self.setCentralWidget(self._centralWidget)
self._centralWidget.setLayout(self.generalLayout)
# Create the display and the buttons
self._createDisplay()
self._createButtons()
def _createDisplay(self):
"""Create the display."""
# Create the display widget
self.display = QLineEdit()
self.progress_bar = QProgressBar()
# Set some display's properties
self.display.setFixedHeight(35)
self.display.setAlignment(Qt.AlignRight)
self.display.setReadOnly(True)
# Add the display to the general layout
self.generalLayout.addWidget(self.display)
self.generalLayout.addWidget(self.progress_bar)
def _createButtons(self):
"""Create the buttons."""
buttonsLayout = QGridLayout()
self.button1 = QPushButton("Start")
self.button1.setFixedSize(80, 40)
self.button2 = QPushButton("Clear")
self.button2.setFixedSize(80, 40)
buttonsLayout.addWidget(self.button1)
buttonsLayout.addWidget(self.button2)
self.generalLayout.addLayout(buttonsLayout)
def setDisplayText(self, text):
"""Set display's text."""
self.display.setText(text)
self.display.setFocus()
def clearDisplay(self):
"""Clear the display."""
self.setDisplayText("")
def msgBox(self, text):
msg_box = QMessageBox()
msg_box.setIcon(QMessageBox.Question)
msg_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
msg_box.setText(text)
msg_box.setDefaultButton(QMessageBox.Cancel)
ret_val = msg_box.exec_()
if ret_val == QMessageBox.Ok:
return True
else:
return False
class Model:
def __init__(self):
self.counter = ''
self.i = ''
def countdown(self, counter):
self.i = 0
self.counter = counter
while self.i < self.counter:
self.i+=1
time.sleep(1)
if self.i == 5:
user_clicked = yield("Please click okay to continue")
if user_clicked is False:
raise StopIteration
class Controller:
def __init__(self, view, model):
self._view = view
self._model = model
self._connect_settings_signals()
def _set_message(self):
self._view.progress_bar.setMaximum(10)
x = threading.Thread(target=self._start_countdown, args=(10,))
x.start()
while x.is_alive():
self._view.progress_bar.setValue(self._model.i)
x.join()
self._view.setDisplayText("Countdown complete!")
def _start_countdown(self, count):
coroutine = self._model.countdown(count)
val = coroutine.__next__()
while val is not None:
print(val)
reply = self._view.msgBox(val)
if reply is False:
coroutine.send(False)
val = coroutine.__next__()
def _clear_message(self):
self._view.progress_bar.setValue(0)
self._view.clearDisplay()
def _connect_settings_signals(self):
self._view.button1.clicked.connect(self._set_message)
self._view.button2.clicked.connect(self._clear_message)
def main():
"""Main function."""
# Create an instance of `QApplication`
pycalc = QApplication(sys.argv)
# Show the calculator's GUI
view = ExampleGUI()
view.show()
model = Model()
# Create instances of the model and the controller
ctrl = Controller(view=view, model=model)
# Execute calculator's main loop
sys.exit(pycalc.exec_())
if __name__ == "__main__":
main()