今天介绍一个PyQt5中利用MVC设计模式构建GUI的例子,这个案例来源于《MATLAB面向对象编程——从入门到设计模式(第2版)》第7章内容,关于存取款的GUI工具设计,详情请参考127~160页面。
利用PyQt5最终创建的界面如下:
接下来聊一聊,具体的实现细节。
与Matlab设计的版本对比,唯一的区别在于事件处理机制的实现方式不同而已。
PyQt5/Qt 中称为信号和槽,用于对象之间的通信,当指定事件发生,一个事件信号会被发射,槽可以被任何Python脚本调用。当和槽连接的信号被发射时,槽会被调用。自定义事件由PyQt5.QtCore中的pyqtSignal方法完成。
Matlab 中的handle类也已经帮我们实现好了事件处理机制,除了控件自带的,诸如 Callback、ButtonPushedFcn等属性(也可以理解成内置事件)外,也可以自定义事件(events定义),然后通过notify方法进行事件的注册(对应于Qt中的信号发射!),最后由addlistener监听事件(相当于槽的作用)。
实现的模型类源码如下:
# !/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()
由语句balance_changed = pyqtSignal()自定义了一个事件信号:balance_changed。在模型类中,当取款或存款发生时,余额发生了改变,即balance_changed事件信号触发了,会发布(发射)消息(通过绑定emit()方法)。接下来需要在视图类中定义所谓的槽函数,即监听balance_changed事件信号,做出响应。
视图类的源码如下:
# !/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('存取款界面') 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)
对于按钮控件,需要connect方法监听该事件信号: self.m_obj.balance_changed.connect(self.update_balance)
控制器类源码如下:
# !/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)
最后,我们可以自定义脚本 balanceApp.py 将MVC的源代码组合起来,就可以运行出这个GUI小工具了,具体如下动图所示:
至此,我们介绍了一个比较完整的利用MVC设计模式构建GUI的方法!希望您喜欢,并且可以从中获得有用的东西。
本文完整代码,请在gzh内回“pyqt5_mvc”进行下载。
【往期推荐】
-
手把手教你,一个案例学会用Matlab App Designer设计文字识别工具(附源码)
-
矩阵2-范数化的向量化方法 (qq.com)
-
texStudio主题配置 (qq.com)
-
送福利啦 (qq.com)
-
如何用Matlab一键下载B站高清视频(下) (qq.com)
-
Python中的装饰器 (qq.com)
-
MATLAB 风格指南 2.0 (qq.com)
-
匿名函数(Anonymous Function) (qq.com)
-
猜猜今天的干货有哪些? (qq.com)
-
分享爬取Matlab中文论坛基础讨论的源代码 (qq.com)
-
如何用Matlab一键下载B站高清视频(上) (qq.com)
-
爬取某学者主页上的文献 (qq.com)