首页 > 其他分享 >利用MVC设计模式构建GUI(PyQt5版)

利用MVC设计模式构建GUI(PyQt5版)

时间:2022-10-10 14:59:50浏览次数:72  
标签:qq 设计模式 obj text GUI PyQt5 btn balance self

今天介绍一个PyQt5中利用MVC设计模式构建GUI的例子,这个案例来源于《MATLAB面向对象编程——从入门到设计模式(第2版)》第7章内容,关于存取款的GUI工具设计,详情请参考127~160页面。

利用PyQt5最终创建的界面如下:

接下来聊一聊,具体的实现细节。

与Matlab设计的版本对比,唯一的区别在于事件处理机制的实现方式不同而已。

PyQt5/Qt 中称为信号和槽,用于对象之间的通信,当指定事件发生,一个事件信号会被发射,槽可以被任何Python脚本调用。当和槽连接的信号被发射时,槽会被调用。自定义事件由PyQt5.QtCore中的pyqtSignal方法完成。

Matlab 中的handle类也已经帮我们实现好了事件处理机制,除了控件自带的,诸如 CallbackButtonPushedFcn等属性(也可以理解成内置事件)外,也可以自定义事件(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的方法!希望您喜欢,并且可以从中获得有用的东西。

本文完整代码,请在公众号内回复“pyqt5_mvc”进行下载。

【往期推荐】

标签:qq,设计模式,obj,text,GUI,PyQt5,btn,balance,self
From: https://www.cnblogs.com/qpwz/p/16775666.html

相关文章

  • SAP GUI 修改轻松访问 easy access的背景图片
    0x01SAPgui提供了丰富的界面风格设定功能,跟Windows桌面主题一样,可以任意设定自己喜欢的颜色风格。不过美中不足,它的背景图片却比较单调,天天看惯了正式系统的蔚蓝水池或......
  • SAP GUI 更改登录界面显示信息
    0x01简单说明在SAPGUI的登录界面,左部输入登录信息如客户端、用户名、密码等,右部空余部分可维护一些登录信息文本,如登录的产品、客户端说明及注意事项等,此项操作详见SAP......
  • easygui库
    根据需求,EasyGui在buttonbox()上建立了一系列的函数供调用。1、msgBox()msgbox(msg='(Yourmessagegoeshere)',title='',ok_button='OK',image=None,root=None)m......
  • 一起学习设计模式:备忘录模式——软件的“后悔药”
    备忘录模式——软件的“后悔药”备忘录是一种行为设计模式,允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态,并将其保存下来。备忘录模式就像是软件中的“后悔药......
  • 设计模式-行为型模式之模板方法
    定义抽象基类,规范接口内部方法执行顺序在进阶篇中,没专门提过抽象基类,在这里顺便就提一下抽象基类的核心特征:不能被直接实例化相反,抽象基类和元类一样,一般都被当......
  • Java设计模式 —— 组合模式
    9组合模式9.1组合模式概述CompositePattern:组合多个对象形成树形结构以表示具有部分-整体关系的层次结构。组合模式使得客户端可以统一处理单个对象和组合对象。......
  • 3 设计模式-建造者模式
    建造者模式在现实生活中如果我们需要制造一个比较复杂的东西,比如手机,台式电脑,或者汽车等。如果我们要制造一台电脑的话我们会先将电脑所需的各个部件买回来然后在组装起......
  • 无需内嵌代码的全新GUI截图方案在TouchGFX,ThreadX GUIX,emWin,LVGL,AWTK全部测试通过,含多
    搞GUI这么多年来,这个问题一直是个心病,通过这段时间的研究,终于有个产品样子了。早期包括现在做产品效果展示,需要截屏时,很多时候依然采用的SD卡/U盘这种的古老方案,不仅麻烦,而......
  • PyQt5的安装
    pipinstallPyQt5pipinstallPyQt5-tools 在路径下venv\Lib\site-packages\pyqt5_tools\Qt\bin找到designer.exe  life2coding.pyimportsysfromPyQt5.QtC......
  • 设计模式 -- Facade(门面模式)
    门面模式(Facade)系统间耦合的复杂度对于客户系统和子系统之前存在很多的耦合的情况,如果不考虑设计的情况,那么会形成A方案的情况,系统的依赖严重,维护性大大降低。如果在......