Today, we introduce an example of using MVC design pattern to build GUI in PyQt5. This case comes from Chapter 7 of MATLAB object-oriented programming - from introduction to design pattern (version 2). For details about the GUI tool design of deposit and withdrawal, please refer to pages 127 ~ 160.
The final interface created by PyQt5 is as follows:
Next, let's talk about the specific implementation details.
Compared with the version designed by Matlab, the only difference is that the implementation of event processing mechanism is different.
PyQt5/Qt is called signal and slot, which is used for communication between objects. When a specified event occurs, an event signal will be transmitted, and the slot can be called by any Python script. When the signal connected to the slot is transmitted, the slot will be called. The custom event is completed by the pyqtSignal method in PyQt5.QtCore.
The handle class in Matlab has also helped us to implement the event handling mechanism. In addition to the control's own attributes such as Callback and ButtonPushedFcn (which can also be understood as built-in events), you can also customize events (defined by events), then register events through the notify method (corresponding to signal transmission in Qt!), and finally listen to events by addlistener (equivalent to the function of the groove).
The source code of the implemented model class is as follows:
# !/usr/bin/env python3 # -*- coding:utf-8 -*- from PyQt5.QtCore import QObject, pyqtSignal class BalanceModel(QObject): balance_changed = pyqtSignal() def __init__(self, balance): super(BalanceModel, self).__init__() self.balance = balance def withdraw(self, val): self.balance -= val self.balance_changed.emit() def deposit(self, val): self.balance += val self.balance_changed.emit()
The statement balance_changed = pyqtSignal() defines an event signal: balance_changed. In the model class, when withdrawal or deposit occurs, the balance changes, that is, the balance_changed event signal is triggered, and a message will be published (transmitted) (by binding the emit() method) . next, you need to define the so-called slot function in the view class, that is, listen to the balance_changed event signal and respond.
The source code of the view class is as follows:
# !/usr/bin/env python3 # -*- coding:utf-8 -*- from PyQt5.QtWidgets import (QWidget, QGridLayout, QLabel, QLineEdit, QPushButton) from PyQt5.QtCore import Qt from BalanceController import BalanceController class BalanceView(QWidget): def __init__(self, m_obj): super(BalanceView, self).__init__() self.m_obj = m_obj self.c_obj = self.make_controller() # Controller object self.balance_label = None self.balance_text = None self.rmb_label = None self.rmb_text = None self.withdraw_btn = None self.deposit_btn = None self.build_app() self.attach2controller(self.c_obj) self.m_obj.balance_changed.connect(self.update_balance) def build_app(self): self.setVisible(False) self.resize(300, 120) self.setWindowTitle('Deposit and withdrawal interface') self.balance_label = QLabel('Balance') self.balance_label.setAlignment(Qt.AlignRight) self.balance_text = QLineEdit() self.balance_text.setAlignment(Qt.AlignRight) self.balance_text.setReadOnly(True) self.balance_text.setText('0') self.rmb_label = QLabel('RMB') self.rmb_label.setAlignment(Qt.AlignRight) self.rmb_text = QLineEdit() self.rmb_text.setAlignment(Qt.AlignRight) self.rmb_text.setText('0') self.withdraw_btn = QPushButton('withdraw') self.withdraw_btn.setAutoFillBackground(True) self.deposit_btn = QPushButton('deposit') main_layout = QGridLayout(self) main_layout.setHorizontalSpacing(15) main_layout.setVerticalSpacing(15) main_layout.addWidget(self.balance_label, 0, 0, 1, 2) main_layout.addWidget(self.balance_text, 0, 2, 1, 2) main_layout.addWidget(self.rmb_label, 1, 0, 1, 2) main_layout.addWidget(self.rmb_text, 1, 2, 1, 2) main_layout.addWidget(self.withdraw_btn, 2, 0, 1, 2) main_layout.addWidget(self.deposit_btn, 2, 2, 1, 2) self.setLayout(main_layout) self.setVisible(True) self.update_balance() def update_balance(self): self.balance_text.setText(str(self.m_obj.balance)) def make_controller(self): controller = BalanceController(self, self.m_obj) return controller def attach2controller(self, controller): self.withdraw_btn.clicked.connect(controller.withdraw_btn_callback) self.deposit_btn.clicked.connect(controller.deposit_btn_callback)
For button controls, the connect method is required to listen for the event signal: self.m_obj.balance_changed.connect(self.update_balance)
The source code of the controller class is as follows:
# !/usr/bin/env python3 # -*- coding:utf-8 -*- class BalanceController: def __init__(self, v_obj, m_obj): self.v_obj = v_obj self.m_obj = m_obj def withdraw_btn_callback(self): val = float(self.v_obj.rmb_text.displayText()) self.m_obj.withdraw(val) def deposit_btn_callback(self): val = float(self.v_obj.rmb_text.displayText()) self.m_obj.deposit(val)
Finally, we can customize the script balanceApp.py and combine the MVC source code to run this GUI gadget, as shown in the following figure:
So far, we have introduced a relatively complete method of building GUI using MVC design pattern! I hope you like it and can get useful things from it.
Please go back to "pyqt5#u MVC" in gzh to download the complete code of this article.
[recommended in previous periods]