

使用 PyQt 快速搭建带有 GUI 的应用(2)–制作计算器 | 文艺数学君
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.

摘要在本文中,我们会用上一章学习到的 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。
下面我们会依次对上面的三个模块的代码进行介绍。我们将这三个模块分别放在三个文件中,总的文件结构如下所示:

- calcModel.py,包含 Model 的模块,主要控制运算。
- calcView.py,包含计算器的界面。
- calcController.py,用来连接 Model 和 View 这两个模块。
- pycalc.py,主函数
Model 模块
Model 模块主要是负责程序的主要逻辑部分的。在我们这个「计算器」的例子中,我们就是要把输入的式子进行计算,得到运算结果。我们可以使用 eval 来完成相关的操作。如下所示,eval 可以对给定的字符串进行运算:

于是,我们构建一个函数,输入是字符串,输出是对应的计算结果,如下所示(写入 calcModel.py
文件中):
- ERROR_MSG = 'ERROR' # 遇到除数是 0 的时候的报错
- def evaluateExpression(expression):
- """将 str 类型的表达式使用 eval 来计算得到结果, 例如 eval('1+1')=2
- Args:
- expression (str): 计算表达式, 例如 '1+2'
- result = str(eval(expression))
- except Exception:
- result = ERROR_MSG
- return result
View 模块
在 View 模块中,我们创建整个应用的主界面。整个界面中有两个大的部件,分别是上面用来显示数字的组件,和按钮的组件,所以整体使用 QVBoxLayout
。在按钮部分使用 QGridLayout
。我们在这里还定义了一些方法,例如刷新显示。
下面是完整的代码,十分建议看着注释,自己亲自敲一遍。
- from PyQt5.QtCore import Qt
- from PyQt5.QtWidgets import QMainWindow, QWidget, QGridLayout, QLineEdit, QPushButton, QVBoxLayout
- class PyCalcUi(QMainWindow):
- """计算器的主界面
- def __init__(self) -> None:
- super().__init__()
- self.setWindowTitle('PyCalc')
- self.setFixedSize(235, 235) # 不可以缩放
- # Main Windows 必须要 Central Widget
- self.generalLayout = QVBoxLayout()
- self._centralWidget = QWidget() # 这里可以放不同的 sub Widgets
- self.setCentralWidget(self._centralWidget)
- self._centralWidget.setLayout(self.generalLayout)
- # 创建 按钮 和 显示
- self._createDisplay()
- self._createButtons()
- def _createDisplay(self):
- """用来显示计算器顶部的数字
- self.display = QLineEdit()
- # 设置 display 的属性
- self.display.setFixedHeight(35)
- self.display.setAlignment(Qt.AlignRight) # 右对齐
- self.display.setReadOnly(True)
- # 设置布局
- self.generalLayout.addWidget(self.display)
- def _createButtons(self):
- """显示计算器的按键
- self.buttons = {}
- buttonLayout = QGridLayout() # 按钮的布局
- # 记录按钮的文字和坐标
- buttons = {'7': (0, 0),
- '8': (0, 1),
- '9': (0, 2),
- '/': (0, 3),
- 'C': (0, 4),
- '4': (1, 0),
- '5': (1, 1),
- '6': (1, 2),
- '*': (1, 3),
- '(': (1, 4),
- '1': (2, 0),
- '2': (2, 1),
- '3': (2, 2),
- '-': (2, 3),
- ')': (2, 4),
- '0': (3, 0),
- '00': (3, 1),
- '.': (3, 2),
- '+': (3, 3),
- '=': (3, 4),
- for binText, pos in buttons.items():
- self.buttons[binText] = QPushButton(binText)
- self.buttons[binText].setFixedSize(40, 40)
- buttonLayout.addWidget(self.buttons[binText], pos[0], pos[1])
- # 将 button layout 添加到 general layout
- self.generalLayout.addLayout(buttonLayout)
- def setDisplayText(self, text):
- """设置 计算器显示器显示的内容
- self.display.setText(text)
- self.display.setFocus() # 将光标聚焦在显示屏上
- def getdisplayText(self):
- """返回显示器中现在的内容
- return self.display.text()
- def clearDisplay(self):
- """将显示器的内容设置为空
- self.setDisplayText('')
在有了这一个部分之后,我们就有了整体的效果,如下所示:

Controller 模块
在这一部分中我们完成 Model
与 View
之间的连接。
- 定义
_buildExpression
方法,是每个按键按下后,需要刷新屏幕的显示,例如按下数字 5 那么屏幕上就需要显示数字 5. - 定义
_calculateResult
方法,按下等号后,对显示的式子进行计算。 - 我们对 View 中每一个组件(这里是计算器中每一个按键)都进行绑定,这里的
_connectSignals
方法,数字键和等号这两个键绑定的是不同的。
- from functools import partial
- class PyCalcCtrl(object):
- def __init__(self, model, view) -> None:
- super().__init__()
- self._view = view # UI 界面对应的类
- self._model = model # 用于计算
- # connect signal and slots
- self._connectSignals() # 初始化
- def _calculateResult(self):
- """调用 model, 来计算结果并更新 DisplayText
- result = self._model(expression=self._view.getdisplayText()) # 得到计算结果
- self._view.setDisplayText(result) # 将计算结果用于显示
- def _buildExpression(self, sub_exp):
- """修改计算器显示界面
- Args:
- sub_exp (str): 输入的运算符
- expression = self._view.getdisplayText() + sub_exp
- self._view.setDisplayText(expression)
- def _connectSignals(self):
- """对每一个按键进行功能函数的绑定
- for btnText, btn in self._view.buttons.items():
- if btnText not in ('=', 'C'):
- btn.clicked.connect(partial(self._buildExpression, sub_exp=btnText))
- self._view.buttons['C'].clicked.connect(self._view.clearDisplay)
- self._view.buttons['='].clicked.connect(self._calculateResult)
再有了上面 Model,View 和 Controller 三个模块之后,我们需要将三者组合在一起。完整的代码如下所示:
- import sys
- from PyQt5.QtWidgets import QApplication
- from calcView import PyCalcUi
- from calcController import PyCalcCtrl
- from calcModel import evaluateExpression
- def main():
- # 创建一个 Application
- pycalc = QApplication(sys.argv)
- # 展示界面
- view = PyCalcUi()
- view.show()
- # 创建 model 和 controller
- model = evaluateExpression
- PyCalcCtrl(view=view, model=model)
- # 执行 event loop
- sys.exit(pycalc.exec_())
- if __name__ == '__main__':
- main()
主要有这样的几个步骤:
- 创建一个 Application
- 创建 View 和 Model
- 创建 Controller,将 Model 与 View 连接在一起
最后我们运行上面的代码,就完成了一个「计算器」的制作。最终的效果如下所示:

Recommend
-
9
使用CRIWARE全家桶制作带有Phil Collins 缔造的80年代经典音效的3D全景场景 发表于2021-02-05 评论0
-
9
摘要这一篇我们主要介绍使用 Qt Designer 来进行 GUI 的设计。我们会通过一个记事本的例子,来了解 Qt Designer 的使用。 使用 PyQt 创建 GUI 的程序大致上有两种方式,1. 使用
-
4
使用 PyQt 快速搭建带有 GUI 的应用(8)–多窗口之间跳转 所属分类:Python库介绍 摘要在...
-
12
使用 PyQt 快速搭建带有 GUI 的应用(7)–打开文件和文件夹 所属分类:Python库介绍 摘要...
-
10
使用 PyQt 快速搭建带有 GUI 的应用(5)–鼠标悬浮操作 所属分类:Python库介绍 摘要本文...
-
10
使用 PyQt 快速搭建带有 GUI 的应用(6)–动态添加组件 所属分类:Python库介绍 摘要本文...
-
12
摘要本文会介绍 PyQt 中的多线程的使用,防止主界面冻结。同时也会介绍在 PyQt 中的进程池与进程之间的通信,进程锁。 PyQt 应用会有一个主线程来执行 event loop。但是如果你在这个线程上,执行了一个比较长时间的任务,那么主界面会被...
-
7
使用 PyQt 快速搭建带有 GUI 的应用(1)–初识 PyQt 所属分类:Python库介绍 摘要本文是对 PyQt 的介绍。本...
-
2
利用Java制作简易计算器 - OSCHINA - 中文开源技术交流社区 majiajue 今天 10:39 ...
-
13
吕毅.NET and Windows App Developer, Microsoft MVP使用 ImageMagick 轻松制作带有多种尺寸的 ico 图标文件 吕毅 发表于 1 小时前 更...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK