I'm creating my first application in Python. Currently I'm implementing the first view with PyQt5 and the MVC pattern. Therefore I created a "main" class that is starting the controller by creating a new controller object (The first programming language I learned was Java, so maybe this is not necassary?). In this controller objects init method I'm creating the first view. The view class itself creates a new QWidget. After the QWidget is created the controller is calling a method of the view (QWidget). This method should show the login screen. To show the login screen a new class (Login) is created. That class is of the type QVBoxLayout and is added to the main view (QWidget). This combination leads to an application that is showing a window with the login. This means main class -> controller -> main window (QWidget) -> login (QVBoxLayout).
Here I have the following question: Is it the correct way to create a main window (QWidget) and use methods to add the inner layout to the window (using other files/classes)? Or should everything be written in one class?
Now I reached the point that my layout and window are displayed correctly. What is missing is the model and how the model is invoked. I searched how I can check if a button was pressed. I found button.clicked.connect(callfunction). This seems to be the right way but how can I call this function from the controller? So that the controller creates the application window and displays the login inside this window. Then the controller listens and waits until the button is pressed. Then the inputs will be forwarded to the model and in the model the credentials will be checked. Here is my sourcecode for the controller with my try on listening to the button:
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")
The code for my Login class:
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()
And my View class:
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)
Further questions:
- Is my understanding of the MVC pattern correct or do I use to many classes?
- Should I listen on the button in the controller or is it correct that the view is invoking a method in the controller?
- Further I implemented that I can call the login
QVBoxLayoutwith an error code to display an error at the bottom of the view. I have not found a way to dynamically change the view from the controller class. The only solution I could imagine is that I "repaint" the content of theQWidgetwith the added error message. Is this the correct solution?
Thanks in advance!
widget.loginButton.clicked.connect(self.loginPressed())towidget.loginButton.clicked.connect(self.loginPressed)without()widgettoself.widgetLoginclass complete.