Отправка информации из одного потока в другой поток в Python и отображение сообщения в исходной архитектуре Thread, PyQT, MVC - PullRequest
0 голосов
/ 21 апреля 2020

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