6

使用 PyQt 快速搭建带有 GUI 的应用(2)–制作计算器 | 文艺数学君

 3 years ago
source link: https://mathpretty.com/13618.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

摘要在本文中,我们会用上一章学习到的 PyQt 5 的基础知识来制作一个计算器,并了解什么是 Model-View-Controller(MVC)的设计模式。

我们在上一篇文章中对 PyQt 的基础知识进行了介绍,例如我们了解了 PyQt 中的 Widgets 个 Layout Managers,也了解了关于 Application,Event loop 的相关概念,最后讲了 Signal and Slots。在这一篇中,我们会将学到的内容进行使用,制作来一个简单的计算器。

这一篇文章主要参考自,Creating a Calculator With Python and PyQt

使用 PyQt 制作计算器

我们会使用 Model-View-Controller(MVC)的设计模式来制作一个计算器。这种设计模式会有三层代码,每一层有不同的功能:

The Model,这部分是模型的核心功能模块,包含主要功能的代码。对于计算器来说,这一部分就是负责计算的模块。

The View,这一部分负责 GUI 界面。会包含所有的组件,与用户的交互等。对于计算器来说,就是在使用过程中我们看到的窗口界面。

The Controller,这一部分是用来连接上面的 Model 和 View 这两个部分。用户的事件会发送给 controller,然后控制 Model 进行工作。Model 的结果会给 controller,controller 在控制 view 的显示。对于计算器来说,这一部分就是会接受用户在界面的操作,让模型执行相应的计算,更新 GUI

下面我们会依次对上面的三个模块的代码进行介绍。我们将这三个模块分别放在三个文件中,总的文件结构如下所示:

使用 PyQt 快速搭建带有 GUI 的应用(2)--制作计算器
  • calcModel.py,包含 Model 的模块,主要控制运算。
  • calcView.py,包含计算器的界面。
  • calcController.py,用来连接 Model 和 View 这两个模块。
  • pycalc.py,主函数

Model 模块

Model 模块主要是负责程序的主要逻辑部分的。在我们这个「计算器」的例子中,我们就是要把输入的式子进行计算,得到运算结果。我们可以使用 eval 来完成相关的操作。如下所示,eval 可以对给定的字符串进行运算:

使用 PyQt 快速搭建带有 GUI 的应用(2)--制作计算器

于是,我们构建一个函数,输入是字符串,输出是对应的计算结果,如下所示(写入 calcModel.py 文件中):

  1. ERROR_MSG = 'ERROR' # 遇到除数是 0 的时候的报错
  2. def evaluateExpression(expression):
  3.     """将 str 类型的表达式使用 eval 来计算得到结果, 例如 eval('1+1')=2
  4.     Args:
  5.         expression (str): 计算表达式, 例如 '1+2'
  6.         result = str(eval(expression))
  7.     except Exception:
  8.         result = ERROR_MSG
  9.     return result

View 模块

在 View 模块中,我们创建整个应用的主界面。整个界面中有两个大的部件,分别是上面用来显示数字的组件,和按钮的组件,所以整体使用 QVBoxLayout。在按钮部分使用 QGridLayout。我们在这里还定义了一些方法,例如刷新显示。

下面是完整的代码,十分建议看着注释,自己亲自敲一遍

  1. from PyQt5.QtCore import Qt
  2. from PyQt5.QtWidgets import QMainWindow, QWidget, QGridLayout, QLineEdit, QPushButton, QVBoxLayout
  3. class PyCalcUi(QMainWindow):
  4.     """计算器的主界面
  5.     def __init__(self) -> None:
  6.         super().__init__()
  7.         self.setWindowTitle('PyCalc')
  8.         self.setFixedSize(235, 235) # 不可以缩放
  9.         # Main Windows 必须要 Central Widget
  10.         self.generalLayout = QVBoxLayout()
  11.         self._centralWidget = QWidget() # 这里可以放不同的 sub Widgets
  12.         self.setCentralWidget(self._centralWidget)
  13.         self._centralWidget.setLayout(self.generalLayout)
  14.         # 创建 按钮 和 显示
  15.         self._createDisplay()
  16.         self._createButtons()
  17.     def _createDisplay(self):
  18.         """用来显示计算器顶部的数字
  19.         self.display = QLineEdit()
  20.         # 设置 display 的属性
  21.         self.display.setFixedHeight(35)
  22.         self.display.setAlignment(Qt.AlignRight) # 右对齐
  23.         self.display.setReadOnly(True)
  24.         # 设置布局
  25.         self.generalLayout.addWidget(self.display)
  26.     def _createButtons(self):
  27.         """显示计算器的按键
  28.         self.buttons = {}
  29.         buttonLayout = QGridLayout() # 按钮的布局
  30.         # 记录按钮的文字和坐标
  31.         buttons = {'7': (0, 0),
  32.                    '8': (0, 1),
  33.                    '9': (0, 2),
  34.                    '/': (0, 3),
  35.                    'C': (0, 4),
  36.                    '4': (1, 0),
  37.                    '5': (1, 1),
  38.                    '6': (1, 2),
  39.                    '*': (1, 3),
  40.                    '(': (1, 4),
  41.                    '1': (2, 0),
  42.                    '2': (2, 1),
  43.                    '3': (2, 2),
  44.                    '-': (2, 3),
  45.                    ')': (2, 4),
  46.                    '0': (3, 0),
  47.                    '00': (3, 1),
  48.                    '.': (3, 2),
  49.                    '+': (3, 3),
  50.                    '=': (3, 4),
  51.         for binText, pos in buttons.items():
  52.             self.buttons[binText] = QPushButton(binText)
  53.             self.buttons[binText].setFixedSize(40, 40)
  54.             buttonLayout.addWidget(self.buttons[binText], pos[0], pos[1])
  55.         # 将 button layout 添加到 general layout
  56.         self.generalLayout.addLayout(buttonLayout)
  57.     def setDisplayText(self, text):
  58.         """设置 计算器显示器显示的内容
  59.         self.display.setText(text)
  60.         self.display.setFocus() # 将光标聚焦在显示屏上
  61.     def getdisplayText(self):
  62.         """返回显示器中现在的内容
  63.         return self.display.text()
  64.     def clearDisplay(self):
  65.         """将显示器的内容设置为空
  66.         self.setDisplayText('')

在有了这一个部分之后,我们就有了整体的效果,如下所示:

使用 PyQt 快速搭建带有 GUI 的应用(2)--制作计算器

Controller 模块

在这一部分中我们完成 ModelView 之间的连接。

  • 定义 _buildExpression 方法,是每个按键按下后,需要刷新屏幕的显示,例如按下数字 5 那么屏幕上就需要显示数字 5.
  • 定义 _calculateResult 方法,按下等号后,对显示的式子进行计算。
  • 我们对 View 中每一个组件(这里是计算器中每一个按键)都进行绑定,这里的 _connectSignals 方法,数字键和等号这两个键绑定的是不同的。
  1. from functools import partial
  2. class PyCalcCtrl(object):
  3.     def __init__(self, model, view) -> None:
  4.         super().__init__()
  5.         self._view = view # UI 界面对应的类
  6.         self._model = model # 用于计算
  7.         # connect signal and slots
  8.         self._connectSignals() # 初始化
  9.     def _calculateResult(self):
  10.         """调用 model, 来计算结果并更新 DisplayText
  11.         result = self._model(expression=self._view.getdisplayText()) # 得到计算结果
  12.         self._view.setDisplayText(result) # 将计算结果用于显示
  13.     def _buildExpression(self, sub_exp):
  14.         """修改计算器显示界面
  15.         Args:
  16.             sub_exp (str): 输入的运算符
  17.         expression = self._view.getdisplayText() + sub_exp
  18.         self._view.setDisplayText(expression)
  19.     def _connectSignals(self):
  20.         """对每一个按键进行功能函数的绑定
  21.         for btnText, btn in self._view.buttons.items():
  22.             if btnText not in ('=', 'C'):
  23.                 btn.clicked.connect(partial(self._buildExpression, sub_exp=btnText))
  24.         self._view.buttons['C'].clicked.connect(self._view.clearDisplay)
  25.         self._view.buttons['='].clicked.connect(self._calculateResult)

再有了上面 Model,View 和 Controller 三个模块之后,我们需要将三者组合在一起。完整的代码如下所示:

  1. import sys
  2. from PyQt5.QtWidgets import QApplication
  3. from calcView import PyCalcUi
  4. from calcController import PyCalcCtrl
  5. from calcModel import evaluateExpression
  6. def main():
  7.     # 创建一个 Application
  8.     pycalc = QApplication(sys.argv)
  9.     # 展示界面
  10.     view = PyCalcUi()
  11.     view.show()
  12.     # 创建 model 和 controller
  13.     model = evaluateExpression
  14.     PyCalcCtrl(view=view, model=model)
  15.     # 执行 event loop
  16.     sys.exit(pycalc.exec_())
  17. if __name__ == '__main__':
  18.     main()

主要有这样的几个步骤:

  • 创建一个 Application
  • 创建 View 和 Model
  • 创建 Controller,将 Model 与 View 连接在一起

最后我们运行上面的代码,就完成了一个「计算器」的制作。最终的效果如下所示:

使用 PyQt 快速搭建带有 GUI 的应用(2)--制作计算器

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK