pythonqt简介(Python和PyQt:构建GUI桌面计算器)
pythonqt简介(Python和PyQt:构建GUI桌面计算器)PyQt6基于Qt v6。因此,它为GUI创建、XML处理、网络通信、正则表达式、线程、SQL数据库、网页浏览和Qt中可用的其他技术提供了类和工具。PyQt6在一组Python模块中实现了许多Qt类的绑定,这些模块被组织在一个名为PyQt6的顶级Python包中。要使PyQt6工作,您需要Python 3.6.1或更高版本。注意:如果您想更深入地了解库的这两个版本之间的区别,请查看关于该主题的PyQt6文档。PyQt是针对Qt的Python绑定,Qt是一组c 库和开发工具,为图形用户界面(gui)提供独立于平台的抽象。Qt还提供了用于网络、线程、正则表达式、SQL数据库、SVG、OpenGL、XML和许多其他强大特性的工具。由RiverBank Computing Ltd开发的PyQt的最新版本是:在本教程中,您将使用PyQt6,因为这个版本是该库的未来。从现在开始,一定要将任何提及Py
尽管web和移动应用程序似乎已经占领了软件开发市场,但传统的图形用户界面(GUI)桌面应用程序仍然有需求。如果您对用python构建这些类型的应用程序感兴趣,那么您将发现有各种各样的库可供选择。它们包括Tkinter、wxPython、PyQt、PySide和其他一些。
在本教程中,您将学习使用Python和PyQt构建GUI桌面应用程序的基础知识。
在本教程中,您将学习如何:
- 使用Python和PyQt创建图形用户界面
- 将应用程序的GUI上的用户事件与应用程序的逻辑连接起来
- 使用适当的项目布局组织PyQt应用程序
- 用PyQt创建一个功能齐全的GUI应用程序
在本教程中,您将使用Python和pyqt创建一个计算器应用程序。这个简短的项目将帮助您掌握基础知识,并让您开始使用这个GUI库。
了解PyQtPyQt是针对Qt的Python绑定,Qt是一组c 库和开发工具,为图形用户界面(gui)提供独立于平台的抽象。Qt还提供了用于网络、线程、正则表达式、SQL数据库、SVG、OpenGL、XML和许多其他强大特性的工具。
由RiverBank Computing Ltd开发的PyQt的最新版本是:
- PyQt5:一个只基于Qt5.x构建的版本。
- PyQt6:一个只基于Qt6.x构建的版本。
在本教程中,您将使用PyQt6,因为这个版本是该库的未来。从现在开始,一定要将任何提及PyQt的内容视为对PyQt6的引用。
注意:如果您想更深入地了解库的这两个版本之间的区别,请查看关于该主题的PyQt6文档。
PyQt6基于Qt v6。因此,它为GUI创建、XML处理、网络通信、正则表达式、线程、SQL数据库、网页浏览和Qt中可用的其他技术提供了类和工具。PyQt6在一组Python模块中实现了许多Qt类的绑定,这些模块被组织在一个名为PyQt6的顶级Python包中。要使PyQt6工作,您需要Python 3.6.1或更高版本。
PyQt6兼容Windows、Unix、Linux、macOS、iOS和Android。如果您正在寻找一个GUI框架来开发在每个平台上都具有本机外观的多平台应用程序,那么这是一个有吸引力的特性。
PyQt6在两种许可下可用:
- The Riverbank Commercial License
- The General Public License (GPL) version 3
您的PyQt6许可证必须与您的Qt许可证兼容。如果您使用GPL许可,那么您的代码也必须使用与GPL兼容的许可。如果您想使用PyQt6创建商业应用程序,那么您的安装需要一个商业许可证。
注意:Qt公司已经为Qt库开发并维护了自己的Python绑定。这个Python库被称为Qt for Python,是官方的Qt for Python。它的Python包称为PySide。
PyQt和PySide都建立在Qt之上,它们的API非常相似,因为它们反映了Qt的API。这就是为什么将PyQt代码移植到PySide可以像更新一些导入一样简单。如果你学会了其中一种,那么你就可以用最少的努力来学习另一种。如果您想更深入地了解这两个库之间的区别,那么可以查看PyQt6 vs PySide6。
如果您需要更多关于PyQt6许可的信息,请查看项目官方文档中的许可 FAQs page。
安装PyQt在系统或开发环境上安装PyQt有几种选择。推荐的选项是使用二元轮。轮子是从Python包索引PyPI安装Python包的标准方法。
在任何情况下,您都需要考虑PyQt6的轮只适用于Python 3.6.1及以后版本。有Linux、macOS和Windows(64位)的轮子。
所有这些轮子都包含相应Qt库的副本,因此不需要单独安装它们。
另一个安装选项是从源代码构建PyQt。这可能有点复杂,所以如果可能的话,您可能想要避免它。如果您确实需要从源代码进行构建,那么请查看库文档在这些情况下的建议。
另外,您可以选择使用包管理器来安装PyQt6,例如Linux上的APT或macOS上的Homebrew。在接下来的几节中,您将了解从不同来源和不同平台上安装PyQt6的一些选项。
使用pip安装虚拟环境大多数时候,您应该创建一个Python虚拟环境,以一种隔离的方式安装PyQt6。要创建一个虚拟环境并在其中安装PyQt6,在命令行上运行以下命令:
Linux和macOS
$ python -m venv venv
$ source venv/bin/activate
(venv) $ python -m pip install pyqt6
Windows
PS> python -m venv venv
PS> venv\Scripts\activate
(venv) PS> python -m pip install pyqt6
这里,您首先使用标准库中的venv模块创建一个虚拟环境。然后激活它,最后使用pip在其中安装PyQt6。注意,安装命令必须安装Python 3.6.1或更高版本才能正常工作。
使用pip进行系统级安装很少需要直接在系统Python环境中安装PyQt。如果您需要进行这种安装,那么在您的命令行或终端窗口中运行以下命令,而不激活任何虚拟环境:
python -m pip install pyqt6
使用此命令,您将直接在系统Python环境中安装PyQt6。您可以在安装完成后立即开始使用库。根据您的操作系统,您可能需要root或管理员权限才能运行此安装。
尽管这是安装PyQt6并立即开始使用它的一种快速方法,但并不推荐使用这种方法。推荐的方法是使用Python虚拟环境,正如您在上一节中所学的那样。
特定于平台的安装一些Linux发行版在它们的存储库中包含PyQt6的二进制包。如果是这种情况,那么可以使用发行版的包管理器安装库。例如,在Ubuntu上,您可以使用以下命令:
$ sudo apt install python3-pyqt6
使用此命令,您将在基本系统中安装PyQt6及其所有依赖项,因此您可以在任何GUI项目中使用该库。注意,这里需要根权限,您可以在这里使用sudo命令调用根权限。
如果您是macOS用户,那么可以使用Homebrew包管理器安装PyQt6。要做到这一点,打开一个终端并运行以下命令:
$ brew install pyqt6
运行此命令后,您将在您的Homebrew Python环境中安装PyQt6,它就可以供您使用了。
如果在Linux或macOS上使用包管理器,则有可能得不到最新版本的PyQt6。如果您想确保您拥有最新的版本,那么使用pip安装会更好。
创建您的第一个PyQt应用程序现在您已经有了一个可以工作的PyQt安装,可以创建您的第一个GUI应用程序了。使用Python和PyQt应用程序。以下是你需要遵循的步骤:
- 从PyQt6.QtWidgets导入QApplication和所有必需的小部件。
- 创建一个QApplication实例。
- 创建应用程序的GUI。
- 显示应用程序的GUI。
- 运行应用程序的事件循环或主循环。
首先,在当前工作目录中创建一个名为hello.py的新文件:
# hello.py
"""Simple Hello World example with PyQt6."""
import sys
# 1. Import QApplication and all the required widgets
from PyQt6.QtWidgets import QApplication QLabel QWidget
首先,导入sys,它将允许您通过exit()函数处理应用程序的终止和退出状态。然后从QtWidgets导入QApplication、QLabel和QWidget QWidget是PyQt6包的一部分。有了这些导入,第一步就完成了。
要完成第二步,您只需要创建QApplication的一个实例。就像创建任何Python类的实例一样:
# hello.py
# ...
# 2. Create an instance of QApplication
app = QApplication([])
在这行代码中,您将创建QApplication的实例。在PyQt中创建任何GUI对象之前,应该先创建应用程序实例。
在内部,QApplication类处理命令行参数。这就是为什么需要将命令行参数列表传递给类构造函数。在本例中,您使用空列表,因为您的应用程序将不处理任何命令行参数。
注意:您经常会发现开发人员传递sys。argv到QApplication的构造函数。该对象包含传入Python脚本的命令行参数列表。如果应用程序需要接受命令行参数,那么应该使用sys。Argv来处理他们。否则,您可以只使用一个空列表,就像在上面的例子中所做的那样。
第三步涉及创建应用程序的GUI。在本例中,您的GUI将基于QWidget类,它是PyQt中所有用户界面对象的基类。
下面是如何创建应用程序的GUI:
# hello.py
# ...# 3. Create your application's GUIwindow = QWidget()
window.setwindowTitle("PyQt App")
window.setGeometry(100 100 280 80)
helloMsg = QLabel("<h1>Hello World!</h1>" parent=window)
helloMsg.move(60 15)
在这段代码中,window是QWidget的一个实例,它提供了创建应用程序窗口或表单所需的所有特性。顾名思义,. setwindowtitle()在应用程序中设置窗口的标题。在本例中,应用程序的窗口将显示PyQt app作为标题。
注意:更准确地说,这一步需要你创建应用程序的顶层或主窗口。术语应用程序的GUI有点通用。通常,应用程序的GUI由多个窗口组成。
您可以使用. setgeometry()来定义窗口的大小和屏幕位置。前两个参数是将放置窗口的x和y屏幕坐标。第三个和第四个参数是窗口的宽度和高度。
每个GUI应用程序都需要小部件或图形化组件来制作应用程序的GUI。在本例中,您使用QLabel小部件helloMsg来显示消息Hello World!在您的应用程序窗口上。
QLabel对象可以显示html格式的文本,因此可以使用HTML元素“
Hello World!”
”提供所需的文本作为h1标题。最后,使用.move()将helloMsg放置在应用程序窗口的坐标(60 15)处。
注意:在PyQt中,您可以使用任何小部件—qwidget的子类—作为顶级窗口。唯一的条件是目标小部件不能有父小部件。当您使用小部件作为顶层窗口时,PyQt会自动为它提供一个标题栏,并将其转换为普通窗口。
小部件之间的父子关系有两个互补的目的。没有父窗口的小部件被认为是主窗口或顶层窗口。相比之下,带有显式父部件的小部件是子部件,它显示在其父部件中。
这种关系也被称为所有权,父母拥有他们的孩子。PyQt所有权模型确保如果您删除一个父小部件,例如顶级窗口,那么它的所有子小部件也将自动删除。
为了避免内存泄漏,您应该始终确保任何QWidget对象都有一个父对象(顶级窗口除外)。
你已经完成了第三步,所以你可以继续最后两个步骤,让你的PyQt GUI应用程序准备好运行:
# hello.py
# ...
# 4. Show your application's GUI
window.show()
# 5. Run your application's event loop
sys.exit(app.exec())
在此代码片段中,在window上调用.show()。对.show()的调用调度一个绘制事件,这是一个绘制组成GUI的小部件的请求。然后将此事件添加到应用程序的事件队列中。您将在后面的部分了解更多关于PyQt事件循环的内容。
最后,通过调用.exec()启动应用程序的事件循环。对.exec()的调用被封装在对sys.exit()的调用中,这允许您在应用程序终止时干净地退出Python并释放内存资源。
你可以用以下命令运行你的第一个PyQt应用程序:
$ python hello.py
当你运行这个脚本时,你会看到一个类似这样的窗口:
您的应用程序显示一个基于QWidget的窗口。窗口显示Hello World!消息。为了显示消息,它使用了一个QLabel小部件。至此,您已经使用PyQt和Python编写了您的第一个GUI桌面应用程序!这不是很酷吗?
考虑到代码风格如果您检查前一节中示例GUI应用程序的代码,那么您将注意到PyQt的API不遵循PEP 8编码风格和命名约定。PyQt是围绕Qt构建的,Qt是用c 编写的,对函数、方法和变量使用驼峰式命名风格。也就是说,在开始编写PyQt项目时,需要决定使用哪种命名风格。
在这方面,PEP 8指出:
新的模块和包(包括第三方框架)应该按照这些标准编写,但是如果现有的库具有不同的风格,则内部一致性是首选。(Source)
如果您想要编写一致的pyqt相关代码,那么您应该坚持框架的编码风格。在本教程中,为了保持一致性,您将遵循PyQt编码风格。您将使用驼峰情况而不是通常的Python snake case.。
学习PyQt的基础知识如果您想熟练地使用这个库开发GUI应用程序,则需要掌握PyQt的基本组件。其中一些组成部分包括:
- 小部件
- 布局管理器
- 对话框
- 主窗口
- 应用程序
- 事件循环
- 信号与插槽
这些元素是任何PyQt GUI应用程序的构建块。它们中的大多数都表示为PyQt6中的Python类。QtWidgets模块。这些因素非常重要。您将在以下几个部分了解更多关于它们的内容。
小部件小部件是矩形图形化组件,您可以将它们放在应用程序的窗口中以构建GUI。小部件有几个属性和方法,允许您调整它们的外观和行为。他们还可以在屏幕上画出自己的形象。
小部件还检测来自用户、窗口系统和其他来源的鼠标单击、按键和其他事件。每当小部件捕获一个事件时,它都会发出一个信号来宣布其状态更改。PyQt拥有丰富而现代的小部件集合。每个小部件都有不同的用途。
一些最常见和最有用的PyQt小部件是:
- 按钮
- 标签
- 行编辑
- 组合框
- 单选按钮
首先是按钮。您可以通过实例化QPushButton来创建按钮,这是一个提供经典命令按钮的类。典型的按钮有“确定”、“取消”、“应用”、“是”、“否”和“关闭”。下面是它们在Linux系统上的样子:
像这样的按钮可能是任何GUI中最常用的小部件。当有人点击它们时,你的应用程序就会命令计算机执行操作。这就是如何在用户单击按钮时执行计算。
接下来是标签,您可以使用QLabel创建标签。标签可以让你以文本或图像的形式显示有用的信息:
你将使用这些标签来解释如何使用你的应用程序的GUI。您可以通过几种方式调整标签的外观。正如您前面看到的,标签甚至可以接受html格式的文本。还可以使用标签指定一个键盘快捷键,将光标焦点移动到GUI上的给定小部件上。
另一个常见的小部件是行编辑,也称为输入框。这个小部件允许您输入单行文本。可以使用QLineEdit类创建行编辑。当需要以纯文本形式获取用户输入时,行编辑非常有用。
下面是Linux系统上的行编辑:
像这样的行编辑自动提供基本的编辑操作,如复制、粘贴、撤消、重做、拖放等。在上图中,您还可以看到第一行上的对象显示占位符文本,以通知用户需要什么样的输入。
组合框是GUI应用程序中另一种基本类型的小部件。您可以通过实例化QComboBox来创建它们。组合框将以一种占用最小屏幕空间的方式为用户提供选项的下拉列表。
下面是一个组合框的例子,它提供了流行编程语言的下拉列表:
这个组合框是只读的,这意味着用户可以从多个选项中选择一个,但不能添加自己的选项。组合框还可以编辑,允许用户动态添加新选项。组合框还可以包含像素图、字符串或两者都包含。
您将了解的最后一个小部件是单选按钮,您可以使用QRadioButton创建它。QRadioButton对象是一个选项按钮,您可以单击它来打开它。当需要用户从多个选项中选择一个时,单选按钮很有用。单选按钮中的所有选项同时显示在屏幕上:
在这个单选按钮组中,在给定的时间内只能选中一个按钮。如果用户选择另一个单选按钮,那么先前选择的按钮将自动关闭。
PyQt有大量的小部件集合。在撰写本文时,有超过40种可供您用于创建应用程序的GUI。在这里,你只研究了一小部分样本。但是,这足以向您展示PyQt的强大功能和灵活性。在下一节中,您将学习如何布局不同的小部件,为您的应用程序构建现代且功能齐全的GUI。
布局管理器既然您已经了解了小部件以及如何使用它们构建GUI,那么您还需要了解如何安排一组小部件,以使GUI既连贯又有功能。在PyQt中,您将发现一些在窗体或窗口中布局小部件的技术。例如,您可以使用.resize()和.move()方法来给出小部件的绝对大小和位置。
然而,这种技术可能有一些缺点。你必须:
- 做很多手工计算来确定每个部件的正确大小和位置。
- 是否进行额外的计算以响应窗口大小调整事件。
- 当窗口的布局以任何方式发生变化时,重新做大部分计算。
另一种技术涉及使用. resizeevent()动态计算小部件的大小和位置。在这种情况下,您将遇到与前一种技术类似的头痛。
最有效和推荐的技术是使用PyQt的布局管理器。它们将提高您的工作效率,降低出错的风险,并提高代码的可维护性。
布局管理器是允许您在应用程序窗口或窗体上调整小部件的大小和位置的类。它们自动适应调整事件和GUI更改的大小,控制所有子部件的大小和位置。
注意:如果您开发国际化的应用程序,那么您可能会看到翻译后的文本在句中被截断。当目标自然语言比原始语言更冗长时,这种情况很可能发生。布局管理器可以根据可用空间自动调整小部件的大小,从而帮助您避免这种常见问题。然而,对于特别冗长的自然语言,这个特性有时会失败。
PyQt提供了四个基本的布局管理器类:
- QHBoxLayout
- QVBoxLayout
- QGridLayout
- QFormLayout
第一个布局管理器类,QHBoxLayout,从左到右水平排列小部件,就像下图中的假设小部件:
在水平布局中,小部件将一个接一个地出现,从左侧开始。下面的代码示例展示了如何使用QHBoxLayout水平排列三个按钮:
# h_layout.py
"""Horizontal layout example."""
import sys
from PyQt6.QtWidgets import (
QApplication
QHBoxLayout
QPushButton
QWidget
)
app = QApplication([])
window = QWidget()
window.setWindowTitle("QHBoxLayout")
layout = QHBoxLayout()
layout.addWidget(QPushButton("Left"))
layout.addWidget(QPushButton("Center"))
layout.addWidget(QPushButton("Right"))
window.setLayout(layout)
window.show()
sys.exit(app.exec())
下面是这个例子如何创建一个水平布局的按钮:
- 第18行创建一个名为layout的QHBoxLayout对象。
- 第19至21行通过调用. addwidget()方法向布局添加三个按钮。
- 第22行使用. setlayout()将布局设置为窗口的布局。
当你从命令行运行python h_layout.py时,你会得到以下输出:
上图显示了三个按钮的水平排列。这些按钮从左到右显示的顺序与您在代码中添加它们的顺序相同。
下一个布局管理器类是QVBoxLayout,它从上到下垂直排列小部件,如下图所示:
每个新的小部件将出现在前一个小部件的下面。这种布局允许您构建垂直布局,并在GUI上从上到下组织您的小部件。
下面是如何创建一个包含三个按钮的QVBoxLayout对象:
# v_layout.py
"""Vertical layout example."""
import sys
from PyQt6.QtWidgets import (
QApplication
QPushButton
QVBoxLayout
QWidget
)
app = QApplication([])
window = QWidget()
window.setWindowTitle("QVBoxLayout")
layout = QVBoxLayout()
layout.addWidget(QPushButton("Top"))
layout.addWidget(QPushButton("Center"))
layout.addWidget(QPushButton("Bottom"))
window.setLayout(layout)
window.show()
sys.exit(app.exec())
在第18行,创建一个名为layout的QVBoxLayout实例。在接下来的三行中,为布局添加三个按钮。最后,通过第22行上的. setlayout()方法,使用布局对象将小部件排列为垂直布局。
当你运行这个示例应用程序时,你会看到一个类似这样的窗口:
该图显示了三个按钮的垂直排列,一个在另一个的下面。按钮的出现顺序与您在代码中添加它们的顺序相同,从上到下。
列表中的第三个布局管理器是QGridLayout。该类在行和列的网格中排列小部件。每个小部件在网格上都有一个相对位置。您可以使用一对坐标(row column)来定义小部件的位置。每个坐标必须是整数。这些坐标对定义了给定小部件将占据网格中的哪个单元格。
网格布局看起来像这样:
QGridLayout利用可用空间,将其划分为行和列,并将每个子部件放入自己的单元格中。
下面是如何在你的GUI中创建一个网格布局:
# g_layout.py
"""Grid layout example."""
import sys
from PyQt6.QtWidgets import (
QApplication
QGridLayout
QPushButton
QWidget
)
app = QApplication([])
window = QWidget()
window.setWindowTitle("QGridLayout")
layout = QGridLayout()
layout.addWidget(QPushButton("Button (0 0)") 0 0)
layout.addWidget(QPushButton("Button (0 1)") 0 1)
layout.addWidget(QPushButton("Button (0 2)") 0 2)
layout.addWidget(QPushButton("Button (1 0)") 1 0)
layout.addWidget(QPushButton("Button (1 1)") 1 1)
layout.addWidget(QPushButton("Button (1 2)") 1 2)
layout.addWidget(QPushButton("Button (2 0)") 2 0)
layout.addWidget(
QPushButton("Button (2 1) 2 Columns Span") 2 1 1 2
)
window.setLayout(layout)
window.show()
sys.exit(app.exec())
在本例中,您将创建一个应用程序,该应用程序使用QGridLayout对象来组织屏幕上的小部件。注意,在本例中,传递给. addwidget()的第二个和第三个参数是整数,定义了每个小部件在网格中的位置。
在第26至28行,您将另外两个参数传递给. addwidget()。这些参数是rowSpan和columnSpan,它们是传递给函数的第四个和第五个参数。可以使用它们使小部件占用多行或多列,就像在示例中所做的那样。
如果你从你的命令行运行这段代码,那么你会看到一个像这样的窗口:
在此图中,可以看到小部件排列在行和列的网格中。最后一个小部件占用两列,正如您在第26至28行中指定的那样。
您将学习的最后一个布局管理器是QFormLayout。这个类以两列布局的方式排列小部件。第一列通常在标签中显示消息。第二列通常包含QLineEdit、QComboBox、QSpinBox等小部件。这允许用户输入或编辑关于第一列中的信息的数据。
下图展示了表单布局在实践中的工作原理:
左列由标签组成,而右列由输入部件组成。如果您正在开发一个数据库应用程序,那么这种布局可能是一个有用的工具,可以提高您在创建输入表单时的工作效率。
下面的例子展示了如何创建一个使用QFormLayout对象来排列小部件的应用程序:
# f_layout.py
"""Form layout example."""
import sys
from PyQt6.QtWidgets import (
QApplication
QFormLayout
QLineEdit
QWidget
)
app = QApplication([])
window = QWidget()
window.setWindowTitle("QFormLayout")
layout = QFormLayout()
layout.addRow("Name:" QLineEdit())
layout.addRow("Age:" QLineEdit())
layout.addRow("Job:" QLineEdit())
layout.addRow("Hobbies:" QLineEdit())
window.setLayout(layout)
window.show()
sys.exit(app.exec())
在这个例子中,第18到23行完成了困难的工作。QFormLayout有一个叫做. addrow()的方便方法。您可以使用此方法向布局中添加包含两个小部件的行。. addrow()的第一个参数应该是一个标签或字符串。然后,第二个参数可以是允许用户输入或编辑数据的任何小部件。在这个特定的示例中,您使用了行编辑。
如果你运行这段代码,你会看到一个像这样的窗口:
上图显示了一个使用表单布局的窗口。第一列包含向用户询问一些信息的标签。第二列显示允许用户输入或编辑所需信息的小部件。
对话框使用PyQt,您可以开发两种类型的GUI桌面应用程序。根据您用来创建主窗体或窗口的类的不同,您将拥有以下其中之一:
- 主窗口样式的应用程序:应用程序的主窗口继承自QMainWindow。
- 对话框风格的应用程序:应用程序的主窗口继承自QDialog。
您将首先从对话框风格的应用程序开始。在下一节中,您将了解主窗口样式的应用程序。
要开发对话框风格的应用程序,您需要创建一个继承自QDialog的GUI类,它是所有对话框窗口的基类。对话框窗口是一个独立的窗口,您可以将其用作应用程序的主窗口。
注意:在主窗口风格的应用程序中,对话窗口通常用于与用户进行简短的通信和交互。
当您使用对话框窗口与用户通信时,这些对话框可以是:
- Modal:阻止对同一应用程序中任何其他可见窗口的输入。你可以通过调用它的.exec()方法来显示模态对话框。
- 无模态:独立于同一应用程序中的其他窗口操作。你可以使用它的.show()方法来显示一个非模态对话框。
对话框窗口还可以提供返回值并具有默认按钮,如Ok和Cancel。
对话框总是一个独立的窗口。如果一个对话框有一个父窗口,那么它将显示在父窗口部件的顶部。与父级的对话框将共享父级的任务栏条目。如果你没有为一个给定的对话框设置parent,那么这个对话框将在系统的任务栏中获得它自己的条目。
下面是一个如何使用QDialog开发对话框式应用程序的例子:
# dialog.py
"""Dialog-style application."""
import sys
from PyQt6.QtWidgets import (
QApplication
QDialog
QDialogButtonBox
QFormLayout
QLineEdit
QVBoxLayout
)
class Window(QDialog):
def __init__(self):
super().__init__(parent=None)
self.setWindowTitle("QDialog")
dialogLayout = QVBoxLayout()
formLayout = QFormLayout()
formLayout.addRow("Name:" QLineEdit())
formLayout.addRow("Age:" QLineEdit())
formLayout.addRow("Job:" QLineEdit())
formLayout.addRow("Hobbies:" QLineEdit())
dialogLayout.addLayout(formLayout)
buttons = QDialogButtonBox()
buttons.setStandardButtons(
QDialogButtonBox.StandardButton.Cancel
| QDialogButtonBox.StandardButton.Ok
)
dialogLayout.addWidget(buttons)
self.setLayout(dialogLayout)
if __name__ == "__main__":
app = QApplication([])
window = Window()
window.show()
sys.exit(app.exec())
这个应用程序稍微复杂一些。以下是这段代码的作用:
- 第16行通过继承QDialog为应用程序的GUI定义了一个Window类。
- 第18行使用super()调用父类的.__init__()方法。这个调用允许您正确地初始化该类的实例。在本例中,父参数被设置为None,因为这个对话框将是您的主窗口。
- 第19行设置窗口的标题。
- 第20行将一个QVBoxLayout对象赋给dialogLayout。
- 第21行将一个QFormLayout对象分配给formLayout。
- 第22至25行向formLayout添加小部件。
- 第26行调用dialogLayout上的. addlayout()。这个调用将表单布局嵌入到全局对话框布局中。
- 第27行定义了一个按钮框,它提供了一个方便的空间来显示对话框的按钮。
- 第28至31行向对话框添加两个标准按钮Ok和Cancel。
- 第32行通过调用. addwidget()将按钮框添加到对话框中。
if __name__ == "__main__":结构包装了应用程序的主代码。这种条件语句在Python应用程序中很常见。它确保缩进代码只在包含的文件作为程序执行而不是作为模块导入时才会运行。有关此构造的更多信息,请查看if name == " main "在Python中做了什么?
注意:在上面示例的第26行,您将注意到布局管理器可以彼此嵌套。您可以通过在容器布局上调用. addlayout()来嵌套布局,并使用嵌套布局作为参数。
上面的代码示例将显示一个类似这样的窗口:
该图显示了您使用QFormLayout对象创建的GUI,该对象用于排列小部件,并使用QVBoxLayout布局用于应用程序的全局布局。
主窗口大多数时候,你的GUI应用程序将是主窗口风格的应用程序。这意味着它们将有一个菜单栏、一些工具栏、一个状态栏和一个作为GUI主要元素的中心小部件。对于你的应用来说,有几个对话框来完成依赖于用户输入的次要操作也是很常见的。
您将继承QMainWindow来开发主窗口样式的应用程序。从QMainWindow派生的类的实例被认为是应用程序的主窗口,并且应该是唯一的。
QMainWindow为快速构建应用程序的GUI提供了一个框架。这个类有自己的内置布局,它接受以下图形组件:
组件 |
窗口中的位置 |
描述 |
一个菜单栏 |
顶部 |
保存应用程序的主菜单 |
一个或多个工具栏 |
边上 |
保存工具按钮和其他小部件,如QComboBox、QSpinBox |
一个核心小部件 |
中间 |
保存窗口的中心小部件,它可以是任何类型,包括复合小部件 |
一个或多个dock小部件 |
围绕着中心部件 |
小的,可移动的,可隐藏的窗户 |
一个状态栏 |
底部 |
保持应用程序的状态栏,显示状态信息 |
如果没有中心小部件,就无法创建主窗口。您需要一个中心部件,即使它只是一个占位符。在这种情况下,可以使用QWidget对象作为中心小部件。
可以使用. setcentralwidget()方法设置窗口的中心小部件。主窗口的布局将允许您只有一个中心小部件,但它可以是单个或复合小部件。下面的代码示例向您展示了如何使用QMainWindow创建一个主窗口样式的应用程序:
# main_window.py
"""Main window-style application."""
import sys
from PyQt6.QtWidgets import (
QApplication
QLabel
QMainWindow
QStatusBar
QToolBar
)
class Window(QMainWindow):
def __init__(self):
super().__init__(parent=None)
self.setWindowTitle("QMainWindow")
self.setCentralWidget(QLabel("I'm the Central Widget"))
self._createMenu()
self._createToolBar()
self._createStatusBar()
def _createMenu(self):
menu = self.menuBar().addMenu("&Menu")
menu.addAction("&Exit" self.close)
def _createToolBar(self):
tools = QToolBar()
tools.addAction("Exit" self.close)
self.addToolBar(tools)
def _createStatusBar(self):
status = QStatusBar()
status.showMessage("I'm the Status Bar")
self.setStatusBar(status)
if __name__ == "__main__":
app = QApplication([])
window = Window()
window.show()
sys.exit(app.exec())
下面是这段代码的工作原理:
- 第15行创建了一个继承自QMainWindow的类Window。
- 第16行定义了类初始化式。
- 第17行调用基类的初始化式。同样,parent参数被设置为None,因为这是应用程序的主窗口,所以它必须没有父窗口。
- 第18行设置窗口的标题。
- 第19行将QLabel设置为窗口的中心小部件。
- 第20至22行调用非公共方法来创建不同的GUI元素:第24至26行使用名为menu的下拉菜单创建主菜单栏。这个菜单将有一个退出应用程序的菜单选项。第28行到31行创建工具栏,它将有一个工具栏按钮,用于退出应用程序。第33至36行创建应用程序的状态栏。
当您使用它们自己的方法实现GUI组件时,就像您在本例中对菜单栏、工具栏和状态栏所做的那样,您正在使您的代码更具可读性和可维护性。
注意:如果你在macOS上运行这个例子,那么你可能会遇到应用程序主菜单的问题。macOS隐藏了某些菜单选项,比如Exit。记住,macOS在屏幕顶部的应用程序条目下显示Exit或Quit选项。
当你运行上面的示例应用程序时,你会看到如下的窗口:
你可以确认,你的主窗口风格的应用程序有以下组件:
- 一个主菜单通常称为菜单
- 一个工具栏与退出工具按钮
- 一个中心小部件,包含一个带有文本消息的QLabel对象
- 窗口底部有一个状态栏
就是这样!您已经学习了如何使用Python和PyQt构建主窗口样式的应用程序。到目前为止,您已经了解了PyQt的小部件集中一些更重要的图形化组件。在接下来的几节中,您将学习与使用PyQt构建GUI应用程序相关的其他重要概念。
应用程序在开发PyQt GUI应用程序时,QApplication是最基本的类。该类是任何PyQt应用程序的核心组件。它管理应用程序的控制流以及它的主要设置。
在PyQt中,QApplication的任何实例都是一个应用程序。每个PyQt GUI应用程序必须有一个QApplication实例。这个类的一些职责包括:
- 处理应用程序的初始化和终结
- 提供事件循环和事件处理
- 处理大多数系统范围和应用程序范围的设置
- 提供对全局信息的访问,例如应用程序的目录、屏幕大小等
- 解析常用的命令行参数
- 定义应用程序的外观
- 提供定位功能
这些只是QApplication的一些核心职责。因此,在开发PyQt GUI应用程序时,这是一个基本类。
QApplication最重要的职责之一是提供事件循环和整个事件处理机制。在下一节中,您将深入了解什么是事件循环以及它是如何工作的。
事件循环GUI应用程序是事件驱动的。这意味着函数和方法是根据用户操作调用的,比如单击按钮、从组合框中选择项、在文本编辑中输入或更新文本、按下键盘上的一个键等等。这些用户操作通常称为事件。
事件由事件循环处理,也称为主循环。事件循环是一个无限循环,在这个循环中,来自用户、窗口系统和任何其他源的所有事件都被处理和分派。事件循环等待事件发生,然后将其分派去执行某些任务。事件循环将继续工作,直到应用程序终止。
所有GUI应用程序都有一个事件循环。当事件发生时,循环检查它是否为终止事件。在这种情况下,循环结束,应用程序退出。否则,事件将被发送到应用程序的事件队列进行进一步处理,并再次循环。在PyQt6中,可以通过在QApplication对象上调用.exec()来运行应用程序的事件循环。
要使事件触发操作,您需要将事件与想要执行的操作连接起来。在PyQt中,可以用信号和槽机制建立连接,这将在下一节中进行探讨。
信号与插槽PyQt小部件充当事件捕获器。这意味着每个小部件都可以捕获特定的事件,如鼠标点击、按键等。作为对这些事件的响应,小部件发出一个信号,这是一种宣布其状态发生变化的消息。
信号本身不执行任何动作。如果你想要一个信号触发一个动作,那么你需要把它连接到一个插槽。这是一个函数或方法,它将在发出相关信号时执行操作。可以使用任何Python可调用对象作为插槽。
如果一个信号连接到一个插槽,那么每当信号发出时就调用该插槽。如果一个信号没有连接到任何插槽,那么什么也不会发生,信号将被忽略。信号和槽的一些最相关的特性包括:
- 一个信号可以连接到一个或多个插槽。
- 一个信号也可以连接到另一个信号。
- 一个槽可以连接到一个或多个信号。
你可以使用下面的语法来连接信号和插槽:
widget.signal.connect(slot_function)
这将连接slot_function到widget.signal。从现在开始,每当.signal被触发时,都会调用slot_function()。
下面的代码展示了如何在PyQt应用程序中使用信号和插槽机制:
# signals_slots.py
"""Signals and slots example."""
import sys
from PyQt6.QtWidgets import (
QApplication
QLabel
QPushButton
QVBoxLayout
QWidget
)
def greet():16 if msgLabel.text():
msgLabel.setText("")
else:
msgLabel.setText("Hello World!")
app = QApplication([])
window = QWidget()
window.setWindowTitle("Signals and slots")
layout = QVBoxLayout()
button = QPushButton("Greet")
button.clicked.connect(greet)28
layout.addWidget(button)
msgLabel = QLabel("")
layout.addWidget(msgLabel)
window.setLayout(layout)
window.show()
sys.exit(app.exec())
在第15行,创建greet(),将其用作插槽。然后在第27行中,将按钮的.clicked信号连接到greeting()。这样,每当用户单击Greet按钮时,就会调用Greet()槽,并且标签对象的文本在Hello World!和一个空字符串:
当您单击Greet按钮时,Hello World!消息在应用程序的主窗口上出现和消失。
注意:每个小部件都有自己的一组预定义信号。您可以在小部件的文档中查看它们。
如果你的slot函数需要接收额外的参数,那么你可以使用functools.partial()传递它们。例如,你可以修改greet()来接受一个参数,如下面的代码所示:
# signals_slots.py
# ...
def greet(name):
if msg.text():
msg.setText("")
else:
msg.setText(f"Hello {name}")
# ...
现在greet()需要接收一个名为name的参数。如果你想把这个新版本的greet()连接到.clicked信号,你可以这样做:
# signals_slots.py
"""Signals and slots example."""
import sys
from functools import partial
# ...
button = QPushButton("Greet")
button.clicked.connect(partial(greeting "World!"))
# ...
要使这段代码正常工作,您需要首先从functools导入partial()。对partial()的调用返回一个函数对象,当使用name="World!"调用时,该函数对象的行为与greet()类似。现在,当用户单击按钮时,消息Hello World!会像以前一样出现在标签上。
注意:您还可以使用lambda函数将信号连接到需要额外参数的槽位。作为练习,请尝试使用lambda而不是functools.partial()来编写上面的示例。
信号和槽机制将用于赋予PyQt GUI应用程序生命。这种机制将允许您将用户事件转换为具体的操作。您可以通过查阅有关该主题的PyQt6文档来更深入地研究信号和槽。
现在您已经了解了PyQt的几个重要概念的基础知识。有了这些知识和库的文档,您就可以开始开发自己的GUI应用程序了。在下一节中,您将构建第一个功能齐全的GUI应用程序。
用Python和PyQt创建一个计算器应用程序在本节中,您将使用模型-视图-控制器(MVC)设计模式开发一个计算器GUI应用程序。这个模式有三层代码,每一层都有不同的角色:
- 该模型负责应用程序的业务逻辑。它包含核心功能和数据。在计算器应用程序中,模型将处理输入值和计算。
- 视图实现了应用程序的GUI。它承载终端用户与应用程序交互所需的所有小部件。视图还接收用户的操作和事件。对于您的示例,视图将是屏幕上的计算器窗口。
- 控制器连接模型和视图以使应用程序工作。用户的事件或请求被发送到控制器,控制器使模型工作。当模型以正确的格式交付所请求的结果或数据时,控制器将其转发给视图。在计算器应用程序中,控制器将从GUI接收目标数学表达式,要求模型执行计算,并使用结果更新GUI。
以下是GUI计算器应用程序如何工作的一步一步描述:
- 用户在视图(GUI)上执行操作或请求(事件)。
- 视图通知控制器用户的操作。
- 控制器获取用户的请求并查询模型以获得响应。
- 模型处理控制器的查询,执行所需的计算,并返回结果。
- 控制器接收模型的响应并相应地更新视图。
- 用户最终在视图上看到请求的结果。
您将使用这个MVC设计用Python和PyQt构建计算器应用程序。
为PyQt计算器应用程序创建框架首先,在一个名为pycalc.py的文件中为应用程序实现一个最小的框架。
如果您希望自己编写项目代码,那么可以在当前工作目录中创建pycalc.py。在您最喜欢的代码编辑器或IDE中打开该文件,并键入以下代码:
# pycalc.py
"""PyCalc is a simple calculator built with Python and PyQt."""
import sys
from PyQt6.QtWidgets import QApplication QMainWindow QWidget
WINDOW_SIZE = 235
class PyCalcWindow(QMainWindow):
"""PyCalc's main window (GUI or view)."""
def __init__(self):
super().__init__()
self.setWindowTitle("PyCalc")
self.setFixedSize(WINDOW_SIZE WINDOW_SIZE)
centralWidget = QWidget(self)
self.setCentralWidget(centralWidget)
def main():
"""PyCalc's main function."""
pycalcApp = QApplication([])
pycalcWindow = PyCalcWindow()
pycalcWindow.show()
sys.exit(pycalcApp.exec())
if __name__ == "__main__":
main()
这个脚本实现了运行基本GUI应用程序所需的所有样板代码。您将使用这个框架来构建计算器应用程序。
下面是这段代码的工作原理:
- 第5行导入sys。这个模块提供了exit()函数,您将使用它干净地终止应用程序。
- 第7行从PyQt6.QtWidgets中导入所需的类。
- 第9行创建一个Python常量,为计算器应用程序保存一个固定的窗口大小(以像素为单位)。
- 第11行创建PyCalcWindow类来提供应用程序的GUI。注意,这个类继承自QMainWindow。
- 第14行定义了类初始化式。
- 第15行调用超类的.__init__()以实现初始化目的。
- 第16行将窗口标题设置为“PyCalc”。
- 第17行使用. setfixedsize()给窗口一个固定的大小。这确保了用户在应用程序执行期间不能调整窗口的大小。
- 第18行和第19行创建一个QWidget对象,并将其设置为窗口的中心小部件。这个对象将是计算器应用程序中所有必需的GUI组件的父组件。
- 第21行定义了计算器的主要函数。使用这样的main()函数是Python中的最佳实践。这个函数提供应用程序的入口点。在main()中,你的程序执行以下操作:第23行创建一个名为pycalcApp的QApplication对象。第24行创建了应用程序窗口pycalcWindow的一个实例。第25行通过在窗口对象上调用.show()来显示GUI。第26行使用.exec()运行应用程序的事件循环。
最后,第29行调用main()来执行计算器应用程序。当运行上述脚本时,屏幕上会出现以下窗口:
就是这样!您已经成功地为GUI计算器应用程序构建了一个功能齐全的应用程序框架。现在可以继续构建项目了。
完成应用的视图
此时您拥有的GUI看起来并不像计算器。您需要通过添加显示目标数学运算的显示器和表示数字和基本数学运算符的按钮键盘来完成这个GUI。您还将添加表示其他所需符号和操作的按钮,比如清除显示。
首先,你需要像下面的代码一样更新你的导入:
# pycalc.py
import sys
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import (
QApplication
QGridLayout
QLineEdit
QMainWindow
QPushButton
QVBoxLayout
QWidget
)
# ...
您将使用QVBoxLayout布局管理器来进行计算器的全局布局。要排列按钮,您将使用一个QGridLayout对象。QLineEdit类将作为计算器的显示,QPushButton将提供所需的按钮。
现在你可以更新PyCalcWindow的初始化式了:
# pycalc.py
# ...
class PyCalcWindow(QMainWindow):
"""PyCalc's main window (GUI or view)."""
def __init__(self):
super().__init__()
self.setWindowTitle("PyCalc")
self.setFixedSize(WINDOW_SIZE WINDOW_SIZE)
self.generalLayout = QVBoxLayout()
centralWidget = QWidget(self)
centralWidget.setLayout(self.generalLayout)
self.setCentralWidget(centralWidget)
self._createDisplay()
self._createButtons()
# ...
您已经添加了突出显示的代码行。你将使用. generallayout作为应用程序的总体布局。在这个布局中,您将把显示器放在顶部,键盘按钮放在底部的网格布局中。
对. _createdisplay()和. _createbuttons()的调用此时还不能工作,因为您还没有实现这些方法。要修复这个问题,首先编写. _createdisplay()。
回到代码编辑器,像下面这样更新pycalc.py:
# pycalc.py
# ...
WINDOW_SIZE = 235
DISPLAY_HEIGHT = 35
class PyCalcWindow(QMainWindow):
# ...
def _createDisplay(self):
self.display = QLineEdit()
self.display.setFixedHeight(DISPLAY_HEIGHT)
self.display.setAlignment(Qt.AlignmentFlag.AlignRight)
self.display.setReadOnly(True)
self.generalLayout.addWidget(self.display)
# ...
在此代码片段中,首先定义一个新常量来保存以像素为单位的显示高度。然后在PyCalcWindow中定义. _createdisplay()。
要创建计算器的显示,可以使用QLineEdit小部件。然后使用DISPLAY_HEIGHT常量为显示设置35个像素的固定高度。显示的文本将左对齐。最后,显示将是只读的,以防止用户直接编辑。最后一行代码将显示添加到计算器的总体布局中。
接下来,您将实现. _createbuttons()方法,为计算器键盘创建所需的按钮。这些按钮将位于网格布局中,因此您需要一种方法在网格中表示它们的坐标。每个坐标对将由一行和一列组成。要表示坐标对,您将使用列表的列表。每个嵌套列表将表示一行。
现在继续,用以下代码更新pycalc.py文件:
# pycalc.py
# ...WINDOW_SIZE = 235
DISPLAY_HEIGHT = 35
BUTTON_SIZE = 40
# ...
在这段代码中,您定义了一个名为BUTTON_SIZE的新常量。您将使用这个常量来提供计算器按钮的大小。在这个特定的例子中,所有的按钮都是一个每边40像素的正方形形状。
通过这个初始设置,您可以编写. _createbuttons()方法。您将使用列表的列表来保存键或按钮及其在计算器键盘上的位置。QGridLayout允许你安排计算器窗口上的按钮:
# pycalc.py
# ...
class PyCalcWindow(QMainWindow):
# ...
def _createButtons(self):
self.buttonMap = {}
buttonsLayout = QGridLayout()keyBoard = [
["7" "8" "9" "/" "C"]
["4" "5" "6" "*" "("]
["1" "2" "3" "-" ")"]
["0" "00" "." " " "="]
]
for row keys in enumerate(keyBoard):
for col key in enumerate(keys):
self.buttonMap[key] = QPushButton(key)
self.buttonMap[key].setFixedSize(BUTTON_SIZE BUTTON_SIZE)
buttonsLayout.addWidget(self.buttonMap[key] row col)
self.generalLayout.addLayout(buttonsLayout)
# ...
首先创建空字典self。buttonMap用于保存计算器按钮。然后,创建一个列表的列表来存储键标签。每一行或嵌套列表将表示网格布局中的一行,而每个键标签的索引将表示布局中相应的列。
然后定义两个for循环。外部循环遍历行,内部循环遍历列。在内部循环中,创建按钮并将它们添加到两个self中。buttonMap buttonsLayout。每个按钮都有一个40x40像素的固定大小,这可以通过. setfixedsize()和BUTTON_SIZE常量来设置。
最后,通过调用. generalayout对象上的. addlayout()将网格布局嵌入到计算器的通用布局中。
注意:当谈到小部件大小时,您很少会在PyQt文档中找到度量单位。测量单位被假定为像素,除非使用QPrinter类,它使用点。
现在,计算器的GUI将优雅地显示显示和按钮。但是,您无法更新显示的信息。你可以通过在PyCalcWindow中添加一些额外的方法来解决这个问题:
方法 |
描述 |
.setDisplayText() |
设置和更新显示的文本 |
.displayText() |
获取当前显示的文本 |
.clearDisplay() |
清除显示的文本 |
这些方法将提供GUI的公共接口,并为您的Python计算器应用程序完成视图类。
下面是一个可能的实现:
# pycalc.py
# ...
class PyCalcWindow(QMainWindow):
# ...
def setDisplayText(self text):
"""Set the display's text."""
self.display.setText(text)
self.display.setFocus()
def displayText(self):
"""Get the display's text."""
return self.display.text()
def clearDisplay(self):
"""Clear the display."""
self.setDisplayText("")
# ...
以下是每种方法的具体功能:
- . setdisplaytext()使用. settext()来设置和更新显示的文本。它还使用. setfocus()将光标的焦点设置在显示器上。
- . displaytext()是一个返回显示当前文本的getter方法。当用户点击计算器键盘上的等号(=)时,应用程序将使用. displaytext()的返回值作为要求值的数学表达式。
- . cleardisplay()将显示的文本设置为空字符串(""),以便用户可以引入一个新的数学表达式。每当用户按下计算器面板上的C按钮时,就会触发此方法。
现在您的计算器的GUI已经准备好使用了!当你运行这个应用程序时,你会看到一个如下面的窗口:
您已经完成了计算器的GUI,它看起来非常流畅!然而,如果您尝试进行一些计算,那么计算器将不会像预期的那样响应。这是因为您还没有实现模型和控制器组件。在下一节中,您将编写计算器的模型。
实现计算器的模型在MVC模式中,模型是负责业务逻辑的代码层。在计算器应用程序中,业务逻辑都是关于基本的数学计算。因此,您的模型将计算用户在计算器的GUI中引入的数学表达式。
计算器的模型还需要处理错误。为此,你将定义以下全局常数:
# pycalc.py
# ...
ERROR_MSG = "ERROR"
WINDOW_SIZE = 235
# ...
如果用户引入了无效的数学表达式,则ERROR_MSG常量是用户将在计算器显示器上看到的消息。
有了以上的更改,你就可以编写应用程序的模型了,在这个例子中,它将是一个单独的函数:
# pycalc.py
# ...
class PyCalcWindow(QMainWindow):
# ...
def evaluateExpression(expression):
"""Evaluate an expression (Model)."""
try:
result = str(eval(expression {} {}))
except Exception:
result = ERROR_MSGreturn result
# ...
在evaluateExpression()中,使用eval()对作为字符串的数学表达式求值。如果计算成功,则返回结果。否则,将返回预定义的错误消息。注意,这个函数并不完美。它有几个重要的问题:
- try…except块不会捕获特定的异常,因此它使用的是Python中不鼓励使用的实践。
- 该函数使用eval(),这可能会导致一些严重的安全问题。
您可以自由地修改该函数,使其更加可靠和安全。在本教程中,您将按原样使用该函数,将重点放在实现GUI上。
为计算器创建控制器类在本节中,您将编写计算器的控制器类。这个类将视图连接到您刚刚编写的模型。您将使用控制器类使计算器执行响应用户事件的操作。
你的控制器类需要执行三个主要任务:
- 访问GUI的公共接口。
- 处理数学表达式的创建。
- 连接所有按钮的。点击信号与适当的插槽。
要执行所有这些操作,稍后将编写一个新的PyCalc类。继续使用以下代码更新pycalc.py:
# pytcalc.py
import sys
from functools import partial
# ...
def evaluateExpression(expression):
# ...
class PyCalc:
"""PyCalc's controller class."""
def __init__(self model view):
self._evaluate = model
self._view = view
self._connectSignalsAndSlots()
def _calculateResult(self):
result = self._evaluate(expression=self._view.displayText())
self._view.setDisplayText(result)
def _buildExpression(self subExpression):
if self._view.displayText() == ERROR_MSG:
self._view.clearDisplay()
expression = self._view.displayText() subExpression
self._view.setDisplayText(expression)
def _connectSignalsAndSlots(self):
for keySymbol button in self._view.buttonMap.items():
if keySymbol not in {"=" "C"}:
button.clicked.connect(
partial(self._buildExpression keySymbol)
)
self._view.buttonMap["="].clicked.connect(self._calculateResult)
self._view.display.returnPressed.connect(self._calculateResult)
self._view.buttonMap["C"].clicked.connect(self._view.clearDisplay)
# ...
在pycalc.py的顶部,从functools导入partial()。您将使用此函数将信号与需要接受额外参数的方法连接起来。
在PyCalc内部,定义类初始化式,它接受两个参数:应用程序的模型和它的视图。然后将这些参数存储在适当的实例属性中。最后,调用. _connectsignalsandslots()来建立所有必需的信号和插槽连接。
在. _calculateresult()中,使用._evaluate()对用户刚刚输入计算器显示的数学表达式求值。然后在计算器视图上调用. setdisplaytext(),用计算结果更新显示文本。
顾名思义,. _buildexpression()方法负责构建目标数学表达式。为此,该方法将初始显示值与用户在计算器键盘上输入的每个新值连接起来。
最后,. _connectsignalsandslots()方法将所有按钮的.clicked信号与控制器类中的适当slots方法连接起来。
就是这样!控制器类已经准备好了。然而,对于所有这些代码作为一个真正的计算器工作,你需要更新应用程序的main()函数如下所示:
# pytcalc.py
# ...
def main():
"""PyCalc's main function."""
pycalcApp = QApplication([])
pycalcWindow = PyCalcWindow()
pycalcWindow.show()
PyCalc(model=evaluateExpression view=pycalcWindow)
sys.exit(pycalcApp.exec())
这段代码创建了PyCalc的一个新实例。PyCalc类构造函数的模型参数保存了对evaluateExpression()函数的引用,而视图参数保存了对pycalcWindow对象的引用,该对象提供了应用程序的GUI。现在PyQt计算器应用程序可以运行了。
运行计算器现在您已经完成了用Python和PyQt编写计算器应用程序,是时候进行现场测试了!如果你从你的命令行运行应用程序,那么你会得到这样的结果:
要使用PyCalc,请用鼠标输入有效的数学表达式。然后,按Enter键或单击等号(=)按钮进行计算,并在计算器的显示器上显示表达式结果。就是这样!您已经使用Python和PyQt开发了第一个功能齐全的GUI桌面应用程序!
额外的工具PyQt6提供了一组有用的附加工具,可以帮助您构建可靠的、现代的、功能齐全的GUI应用程序。与PyQt相关的一些最显著的工具包括Qt Designer和国际化工具包。
Qt Designer允许您使用拖放界面设计和构建图形用户界面。您可以使用这个工具通过使用屏幕上的表单和拖放机制来设计小部件、对话框和主窗口。下面的动画展示了Qt Designer的一些功能:
Qt Designer使用XML .ui文件来存储GUI设计。PyQt包含一个名为uic的模块来帮助处理.ui文件。您还可以使用名为pyyuic6的命令行工具将.ui文件内容转换为Python代码。
注意:要深入了解Qt Designer并更好地理解如何使用该工具创建图形用户界面,请查看Qt Designer和Python:更快地构建您的GUI应用程序。
PyQt6还提供了一套全面的工具,用于将应用程序国际化为本地语言。pylupdate6命令行工具创建和更新翻译(.ts)文件,该文件可以包含接口字符串的翻译。如果您更喜欢GUI工具,那么您可以使用Qt Linguist创建和更新.ts文件,其中包含接口字符串的翻译。
结论图形用户界面(GUI)应用程序仍然占据软件开发市场的很大份额。Python提供了一些框架和库,可以帮助您开发现代而健壮的GUI应用程序。
在本教程中,您学习了如何使用PyQt,它是用Python开发GUI应用程序最流行和最可靠的库之一。现在您知道了如何有效地使用PyQt构建现代GUI应用程序。
在本教程中,您已经学习了如何:
- 使用Python和PyQt构建图形用户界面
- 将用户的事件与应用程序的逻辑连接起来
- 使用适当的项目布局组织PyQt应用程序
- 使用PyQt创建一个真实的GUI应用程序
现在,您可以使用Python和PyQt知识为自己的桌面GUI应用程序注入活力。这不是很酷吗?
虽然PyQt6文档是这里列出的第一个资源,但它的一些重要部分仍然缺失或不完整。幸运的是,您可以使用Qt文档来填补空白。