Отправка информации из модели в представление, MVC архитектура, PyQT5 - PullRequest
0 голосов
/ 09 апреля 2020

Я пытаюсь создать приложение с PyQT5 с использованием архитектуры MVC, и у меня возникают проблемы с пониманием того, как отправить часть информации из модели в представление. В приведенном ниже примере приложения в модели запущен таймер обратного отсчета, и я хочу, чтобы индикатор прогресса в представлении отслеживал его прогресс. Но я не уверен, как отправить информацию в представление из модели во время выполнения метода в модели. В моем случае, progress_bar обновляется только после завершения выполнения метода model.counter. Что было бы изящным способом справиться с этим? Мне нужно, чтобы прогресс_бара обновлялся по мере обновления файла model.i.

import sys
import time

from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget
from PyQt5.QtWidgets import QGridLayout, QLineEdit, QPushButton, QVBoxLayout, QProgressBar
from PyQt5.QtCore import Qt


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("")


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)
        return True


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)
        reply = self._model.countdown(10)
        self._view.progress_bar.setValue(self._model.i)
        if reply:
            self._view.setDisplayText("Countdown complete!")

    def _clear_message(self):
        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()

1 Ответ

0 голосов
/ 09 апреля 2020

То, что sleep (1) блокирует операцию, и событие l oop возвращается к _set_message только после завершения обратного отсчета. Я бы перенес обновление модели и l oop из модели обратно в контроллер. (Как своего рода управление, говорящее модели обновлять свое значение, подождите немного ...)

Я бы обновил что-то похожее на:

    def _set_message(self):
        self._view.progress_bar.setMaximum(10)

        self.i = 0
        while self.i < 10:
            self.i+=1

            self._model.i += 1
            self._view.progress_bar.setValue(self._model.i)
            time.sleep(1)

        self._view.setDisplayText("Countdown complete!")

Если бы вы настаивали на цикле и Если вы спите в модели (я не думаю, что это хорошая идея), вам придется погрузиться в многопоточность, создать отдельный поток для этой операции и оставить главное событие l oop разблокированным для перерисовки индикатора выполнения. (Имхо)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...