Python - PyQt5 - MVC

Chr*_*oph 3 python model-view-controller pyqt pyqt5

我正在用 Python 创建我的第一个应用程序。目前我正在使用 PyQt5 和 MVC 模式实现第一个视图。因此,我创建了一个“主”类,它通过创建一个新的控制器对象来启动控制器(我学习的第一种编程语言是 Java,所以也许这不是必需的?)。在这个控制器对象 init 方法中,我创建了第一个视图。视图类本身会创建一个新的QWidget. 后QWidget创建所述控制器被调用的视图的方法(QWidget)。此方法应显示登录屏幕。为了显示登录屏幕,创建了一个新类(登录)。该类属于该类型QVBoxLayout并已添加到主视图 ( QWidget)。这种组合会导致一个应用程序显示一个带有登录信息的窗口。这意味着主类 -> 控制器 ->QWidget) -> 登录 ( QVBoxLayout)。

在这里我有以下问题:创建主窗口(QWidget)并使用方法将内部布局添加到窗口(使用其他文件/类)是否正确?还是应该将所有内容写在一个类中?

现在我达到了正确显示我的布局和窗口的地步。缺少的是模型以及模型的调用方式。我搜索了如何检查按钮是否被按下。我发现button.clicked.connect(callfunction). 这似乎是正确的方法,但如何从控制器调用此函数?以便控制器创建应用程序窗口并在此窗口内显示登录信息。然后控制器监听并等待按钮被按下。然后输入将被转发到模型,并在模型中检查凭据。这是我尝试听按钮的控制器的源代码:

class Controller(object):

    def __init__(self):
        # Applikation starten und Login anzeigen
        app = QApplication(sys.argv)
        widget = View()
        widget.showLogin(0, "")
        widget.loginButton.clicked.connect(self.loginPressed())
        sys.exit(app.exec_())

    def loginPressed(self):
        widget.showLogin(1, "err1")
Run Code Online (Sandbox Code Playgroud)

我的登录类的代码:

def __init__(self):
    super().__init__()

    # Zum vertikalen zentrieren des Inhalts
    self.addStretch()

    # Label (Bild) erstellen und zum Layout hinzufügen
    label = QLabel()
    pixmap = QPixmap(pathLogo)
    label.setPixmap(pixmap.scaledToWidth(logoWidth, Qt.SmoothTransformation))
    label.setAlignment(Qt.AlignCenter)
    self.addWidget(label)

    # Label für den Nutzername
    usernameLabel = QLabel("Username")
    usernameLabel.setAlignment(Qt.AlignCenter)
    usernameLabel.setStyleSheet("QLabel {color: #ffffff; font-size: 14px; font-weight:bold; "
                                "margin:50px, 0, 5px, 0 ;}")
    self.addWidget(usernameLabel)

    # Eingabefeld für den Nutzername
    uihbox = QHBoxLayout()
    uihbox.addStretch()
    usernameInput = QLineEdit()
    usernameInput.setFixedWidth(150)
    usernameInput.setStyleSheet(
        "QLineEdit {border-radius: 5px; padding: 4px; line-height:12px; padding-left: 5px;}")
    uihbox.addWidget(usernameInput)
    uihbox.addStretch()
    self.addLayout(uihbox)

    # Label für das Passwort
    passwortLabel = QLabel("Passwort")
    passwortLabel.setAlignment(Qt.AlignCenter)
    passwortLabel.setStyleSheet("QLabel {color: #ffffff; font-size: 14px; font-weight:bold; "
                                "margin:15px, 0, 5px, 0 ;}")
    self.addWidget(passwortLabel)

    # Eingabefeld für den Nutzername
    pihbox = QHBoxLayout()
    pihbox.addStretch()
    passwordInput = QLineEdit()
    passwordInput.setFixedWidth(150)
    passwordInput.setEchoMode(QLineEdit.Password)
    passwordInput.setStyleSheet(
        "QLineEdit {border-radius: 5px; padding: 4px; line-height:12px; padding-left: 5px;}")
    pihbox.addWidget(passwordInput)
    pihbox.addStretch()
    self.addLayout(pihbox)

    # Button erstellen
    bihbox = QHBoxLayout()
    bihbox.addStretch()
    loginButton = QPushButton("Login")
    loginButton.setStyleSheet("QPushButton {margin: 25px, 0, 0, 0; border-radius:5px; border: 1px solid white; "
                              "padding-right: 15px; padding-left: 15px; padding-top: 5px; padding-bottom:5px;"
                              "color:white; font-weight:bold; font-size: 14px;}")
    loginButton.setCursor(QCursor(Qt.PointingHandCursor))

    bihbox.addWidget(loginButton)
    bihbox.addStretch()
    self.addLayout(bihbox)

    # Zum vertikalen zentrieren des Inhalts
    self.addStretch()

def showError(self, errCode):
    errMsg = QLabel(err1)
    errMsg.setAlignment(Qt.AlignCenter)
    errMsg.setStyleSheet("QLabel {color:red;}")
    self.addWidget(errMsg)
    self.addStretch()
Run Code Online (Sandbox Code Playgroud)

而我的 View 类:

class View(QWidget):

    # Methode um das Fenster der Applikation zu initialisieren
    def __init__(self):
        super().__init__()

        # Breite und Höhe setzen
        self.resize(initWidth, initHeight)

        # Titel und Icon setzen
        self.setWindowTitle(appTitle)
        self.setWindowIcon(QIcon(pathFavicon))

        # Hintergrund mit der bgColor füllen
        self.setAutoFillBackground(True)
        p = self.palette()
        p.setColor(self.backgroundRole(), QColor(bgColor))
        self.setPalette(p)

        # Anzeigen des Fensters
        self.show()

    # Methode, um Login zu zeigen
    def showLogin(self, err, errcode):
        # Laden des Inhalts mittels Login
        if (err != 0):
            vbox = Login()
            vbox.showError(errcode)
        if (err == 0):
            vbox = Login()

        self.setLayout(vbox)
Run Code Online (Sandbox Code Playgroud)

进一步的问题:

  • 我对 MVC 模式的理解是正确的还是我使用了很多类?
  • 我应该监听控制器中的按钮还是视图调用控制器中的方法是否正确?
  • 此外,我实现了我可以QVBoxLayout使用错误代码调用登录以在视图底部显示错误。我还没有找到从控制器类动态更改视图的方法。我能想象到的唯一解决方案是QWidget使用添加的错误消息“重新绘制” 的内容。这是正确的解决方案吗?

提前致谢!

eyl*_*esc 8

这个想法不是类的数量,而是每个类的任务是什么。

  • 模型是保存信息的实体。
  • 视图是显示信息的实体。
  • 而控制器就是按照一定的逻辑控制视线数据流的控制器。

那么你认为你的类实现了上述内容吗?

在下面的示例中,我展示了如何重新分配这些任务,我的示例不符合@101指出的所有经典 MCV 规则,因为 GUI 具有内部事件处理程序。

import sys
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets


class Model:
    def __init__(self):
        self.username = ""
        self.password = ""

    def verify_password(self):
        return self.username == "USER" and self.password == "PASS"


class View(QtWidgets.QWidget):
    verifySignal = QtCore.pyqtSignal()

    def __init__(self):
        super(View, self).__init__()
        self.username = ""
        self.password = ""
        self.initUi()

    def initUi(self):
        lay = QtWidgets.QVBoxLayout(self)
        title = QtWidgets.QLabel("<b>LOGIN</b>")
        lay.addWidget(title, alignment=QtCore.Qt.AlignHCenter)

        fwidget = QtWidgets.QWidget()
        flay = QtWidgets.QFormLayout(fwidget)
        self.usernameInput = QtWidgets.QLineEdit()
        self.usernameInput.textChanged.connect(partial(setattr, self, "username"))
        self.passwordInput = QtWidgets.QLineEdit(echoMode=QtWidgets.QLineEdit.Password)
        self.passwordInput.textChanged.connect(partial(setattr, self, "password"))
        self.loginButton = QtWidgets.QPushButton("Login")
        self.loginButton.clicked.connect(self.verifySignal)

        flay.addRow("Username: ", self.usernameInput)
        flay.addRow("Password: ", self.passwordInput)
        flay.addRow(self.loginButton)

        lay.addWidget(fwidget, alignment=QtCore.Qt.AlignHCenter)
        lay.addStretch()

    def clear(self):
        self.usernameInput.clear()
        self.passwordInput.clear()

    def showMessage(self):
        messageBox = QtWidgets.QMessageBox(self)
        messageBox.setText("your credentials are valid\n Welcome")
        messageBox.exec_()
        self.close()

    def showError(self):
        messageBox = QtWidgets.QMessageBox(self)
        messageBox.setText("your credentials are not valid\nTry again...")
        messageBox.setIcon(QtWidgets.QMessageBox.Critical)
        messageBox.exec_()


class Controller:
    def __init__(self):
        self._app = QtWidgets.QApplication(sys.argv)
        self._model = Model()
        self._view = View()
        self.init()

    def init(self):
        self._view.verifySignal.connect(self.verify_credentials)

    def verify_credentials(self):
        self._model.username = self._view.username
        self._model.password = self._view.password
        self._view.clear()
        if self._model.verify_password():
            self._view.showMessage()
        else:
            self._view.showError()

    def run(self):
        self._view.show()
        return self._app.exec_()


if __name__ == '__main__':
    c = Controller()
    sys.exit(c.run())
Run Code Online (Sandbox Code Playgroud)