【没钱买ps,PyQt自己写】Day 5 - 开始来设计我们的 controller.py,改以「程序角度」来说明如何建立 PyQt 的系统

看完这篇文章你会得到的成果图

今天我们要延伸昨天的概念,开始来讲解我们如何设计 controller.py

此篇文章的范例程序码 github

https://github.com/howarder3/ironman2021_PyQt5_photoshop/tree/main/day05_pyqt_template

先复习一下 PyQt 的程序逻辑

细节我们在昨天已经有提过了,这个是我们设计「视觉化应用的精神」

接下来我们会以「程序的角度」,来说明怎麽样写这样的程序

以「程序角度」,来说明如何建立 PyQt 的系统

我们设计完 UI.py 後,再来我们要设计 controller.py,
我们可以先看下图,先有个架构理解我们在做什麽:

  • 用「controller.py」去 import「UI.py」来使用,
  • 用「start.py」去 import「controller.py」来使用,

之前在网路上看到的程序码,很多都会将程序进入点也写在这里
并将 controller.py 命名为 start.py 或 strat_UI.py 之类的
这边读者只要有一只程序会有包含「UI.py」、「controller.py」的概念,
相信就能对网路上大部分的范例程序码能够进行初步的解读,
(之前我就是卡在 UI 与 control 的概念整个混在同一支程序码中,所以学得非常混乱XD)

先来看 controller.py 范例,将程序进入点 (start.py) 整在一起

这个范例是我看来不少文章後,做给自己的特制版

  • 第二行的「from UI import Ui_MainWindow」:UI 的部分,请改成你储存的 UI.py 档名

Ui_MainWindow,是 Qt dedigner 预设产生出 .py 档就会取名的 class 封装後的名称,建议没必要不需要特别去更改

from PyQt5 import QtWidgets, QtGui, QtCore
from UI import Ui_MainWindow

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
		# in python3, super(Class, self).xxx = super().xxx
        super(MainWindow, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.setup_control()

    def setup_control(self):
        # TODO
        self.ui.textEdit.setText('Happy World!')


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

说明

上面的范例程序,有调整过适合套用在往後要设计的各种 UI 程序里面,
我们接下来只需要改动的地方都在「setup_control()」之中,

例如像上面范例中的

def setup_control(self):
	# TODO
	self.ui.textEdit.setText('Happy World!')

我们将我们设计的「UI程序」,封装後储存在「self.ui」中,
而 self.ui 里面的 textEdit,就是我们这次修改内容的目标。

我们使用 .setText 修改成 'Happy World!',就能得到以下的结果。

我们使用 Day2 制作出来的 「UI.py」

程序码是一样的,为了不让读者还需要特别回去翻,
我们这边在附上范例一次,请将他存成「UI.py」,
或自行去修改上面提到的「from UI import Ui_MainWindow」的「UI」档名。

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
        self.textEdit.setGeometry(QtCore.QRect(270, 290, 104, 71))
        self.textEdit.setObjectName("textEdit")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.textEdit.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'PMingLiU\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Hello World!</p></body></html>"))

执行

将「controller.py」、「UI.py」准备好後,
执行我们的程序,目前这个 「controller.py」也包含着我们程序的进入点。

python controller.py

结果

  • 我们可以注意到,中间的内文从「Hello World!」变成了「Happy World!」

最後,为了让我们的逻辑在更漂亮一些,我们让 start 与 controller 分离。

为了符合当初我们想的架构,如下图,
我们让 controller.py 独立出来,专心做控制的动作就好,
这样也更符合 Design Pattern 的 「单一职责原则 (SRP)」

真正的实现我们上述所说的:

  • 用「controller.py」去 import「UI.py」来使用

  • 用「start.py」去 import「controller.py」来使用

  • 另外,在 python3 当中,super(MainWindow_controller, self).init() 的写法,
    可以简写为 super().init()

因此,我们将 controller.py 简化为

from PyQt5 import QtWidgets, QtGui, QtCore

from UI import Ui_MainWindow

class MainWindow_controller(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__() # in python3, super(Class, self).xxx = super().xxx
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.setup_control()

    def setup_control(self):
        # TODO
        self.ui.textEdit.setText('Happy World!')

并新增一个 start.py,作为之後程序的入口

from PyQt5 import QtWidgets

from controller import MainWindow_controller

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow_controller()
    window.show()
    sys.exit(app.exec_())

小结

今天我们完成了一支 Qt 程序大致的模板,
之後我们都可以照着这个模板进行後续的开发!


★ 本文也同步发於我的个人网站(会有内容目录与显示各个小节,阅读起来更流畅):【PyQt5】Day 5 - 开始来设计我们的 controller.py,改以「程序角度」来说明如何建立 PyQt 的系统


<<:  DAY5:专案架构介绍(一)

>>:  分散式资料库:New SQL

企划实现(12)

FB登入 第10步:开启 /app/res/values/strings.xml 档案。 FB会自动...

【从零开始的Swift开发心路历程-Day2】牛刀小试

昨天轻松的安装完Xcode环境後,想必各位已经迫不及待想大显身手了吧! 但是吃紧弄破碗,就让我们先来...

Day 14 - UML x Interface — Portal

UML Portal 是什麽? 开始之前,先说一下 Portal 其实是 React 比较常用的 ...

Day 29 实作 admin_bp (2)

前言 快要结束了,今天要继续写 admin_bp。今天的内容会用到 JS,但我不会多加解释。 pos...

在 Linux 上轻松安装 Fcitx 与呒虾米

前言 fctix 这个输入法平台是直接就可从套件管理程序安装呒虾米输入法,我翻了一下资料,fcitx...