龙空技术网

一文全面了解:如何使用Python的界面框架 PyQt 构建 GUI

洪较瘦不着调退役it人 682

前言:

现时小伙伴们对“pythonqtdesigner”大概比较看重,各位老铁们都需要学习一些“pythonqtdesigner”的相关知识。那么小编同时在网上汇集了一些对于“pythonqtdesigner””的相关文章,希望你们能喜欢,姐妹们一起来学习一下吧!

如何使用 PyQt 构建 GUI

<> 14 分钟阅读

介绍

图形用户界面,更广为人知的是GUI,是当今大多数个人计算机的特征。它为不同计算技能水平的用户提供了直观的体验。尽管它们可能会使用更多资源,但由于其点击性质,GUI 应用程序通常是用户友好的。

PyQt 是可用于在 Python 中开发跨平台 GUI 应用程序的工具包之一。如果您已经牢牢掌握了这门语言,它功能强大且易于学习。

本文将向您介绍使用 PyQt 构建 GUI 的基础知识。它要求您具备Python和面向对象编程的基础知识。我们的重点不是解释Python概念,而是主要放在PyQt上。

什么是 PyQt?

PyQt是跨平台应用程序开发框架Qt的Python绑定。使用 PyQt 可以让你使用简单但功能强大的语言(如 Python)开发 GUI 应用程序。它公开了Qt API的所有功能。

Riverbank Computing是PyQt开发和维护背后的公司。它最新的稳定版本是 PyQt6。从发布历史来看,PyQt主要版本的发布周期似乎与Qt的发布周期同步。

在本文中,我们将使用 PyQt5。它需要 Python v3.5 或更高版本,但您也可以使用早期版本的 Python 进行构建。但请注意,PyQt6 需要 Python v3.6.1 或更高版本。

在一头扎进构建 GUI 应用程序之前,您应该知道 PyQt 是双重许可的。这些许可证是GPL v3和Riverbank商业许可证。

如果您根据 GPL v3 许可证获得 PyQt,则需要在兼容许可证下分发代码。同样,您的 PyQt 许可证应该与您的 Qt 许可证保持一致。

我在这里提供的是对 PyQt 许可要求的高级概述。我建议您熟悉要使用的特定版本的 PyQt 的许可要求。

如何安装 PyQt

对于商业许可的 PyQt 版本,您必须在安装之前首先获取许可证。要安装 GPL 许可版本,请运行以下命令以创建虚拟环境并安装 PyQt5。虽然您可以全局安装 PyQt,但建议您使用虚拟环境。

# Create virtual environmentpython3 -m venv env# Activate virtual environmentsource env/bin/activate# Install PyQt5pip install PyQt5

有关详细的安装说明,您应该查看要使用的特定版本的 PyQt 的文档。它有安装GPL和商业版本的说明。该文档还提供了故障排除提示,以防您遇到一些错误。

使用 PyQt 构建一个简单的 GUI

让我们通过构建一个简单的“hello world”GUI来体验PyQt。构建这个简单的应用程序将使后续部分中的工作变得容易得多。

在我们开始之前,这里值得一提的是,PyQt 使用 camelCase 作为方法和属性名称。在本文中,我们将在命名变量和函数时使用 camelCase 以保持一致性,而不是 Python 中推荐的命名约定。

我们将有意使事情变得简单和最小。我假设您在项目目录中创建了一个文件;您可以按照以下步骤将每个步骤中的代码行添加到文件中。app.pyapp.py

步骤 1:导入所需的类

PyQt 带有几个内置模块。但是,在构建 GUI 时,您将最常与之交互的模块是模块。它具有将用于创建 GUI 的类。QtWidgets

因为我们的目标是创建最基本的“hello world”GUI,所以我们将只使用 and 类。首先像这样导入它们:QApplicationQWidgets

from PyQt.QtWidgets import QApplication, QWidgets

您可以以相同的方式导入要在应用程序中使用的其他类。

步骤 2:初始化应用程序

我们需要通过创建 的实例来初始化应用程序。它负责管理应用程序的主要设置和控制流。因此,应在创建与用户界面相关的任何其他对象之前实例化此类。QApplication

application = QApplication([])

有关类职责的更多见解,请查看 Qt 文档。QApplication

在上面的代码中,我们将一个空数组传递给 ,但如果您希望应用程序从命令行接收参数,您也可以传递。如果要作为参数传递,请务必导入。QApplicationsys.argvsyssys.argv

步骤 3:创建主窗口

主窗口(也称为顶级窗口)是一个没有父窗口的小部件。每个 GUI 都必须有一个主窗口。

目前,我们将创建一个实例并使其成为我们的主窗口,如下所示:QWidget

mainWindow = QWidget()mainWindow.setGeometry(0, 0, 350, 400)mainWindow.setWindowTitle('Hello World')

创建 的实例后,还可以调用其他几种方法。对于我们的简单 GUI,我们调用了方法和方法。QwidgetsetGeometrysetWindowTitle

该方法用于在屏幕上定位 GUI 并设置其尺寸。其函数签名为 。前两个参数分别指定屏幕上窗口的 and 坐标,和分别用于设置窗口的宽度和高度。setGeometrysetGeometry(x, y, width, height)xywidthheight

顾名思义,该方法用于设置应用程序的标题。可以将标题作为字符串参数传递。如果您不自己设置,则该窗口将没有标题。setWindowTitle

步骤 4:显示主窗口

默认情况下,我们在上一步中创建的窗口不可见。我们需要通过调用该方法来显示它:show

mainWindow.show()
步骤 5:启动事件循环

最后,您需要通过调用该方法来启动事件循环:application.exec

application.exec()

您也可以改为使用 来启动事件循环。application.exec_()

完成上述所有五个步骤后,您的文件应具有以下代码:app.py

from PyQt5.QtWidgets import QWidget, QApplicationapplication = QApplication([])mainWindow = QWidget()mainWindow.setGeometry(0, 0, 350, 400)mainWindow.setWindowTitle('Hello World')mainWindow.show()application.exec()

与任何其他 Python 脚本一样,您需要使用命令 .您应该能够看到显示的窗口。窗口的外观在很大程度上取决于您的系统。在 Linux 上,它应该类似于下图。app.pypython3 app.py

PyQt 中的主要概念

我们刚刚创建了我们的第一个“hello world”GUI。现在让我们看一些主要概念,这些概念将拓宽我们对 PyQt 的了解。构建生产级 GUI 需要对这些概念有一定程度的熟悉。

部件

像大多数 GUI 工具包一样,小部件是 PyQt GUI 的构建块。您可以使用微件来显示数据、接收用户输入或将其用作对其他相关微件进行分组的容器。

大多数小部件嵌套在其他小部件中,但是,总有一个小部件没有父小部件。如前所述,没有父级的小部件称为窗口。

在 PyQt 中创建小部件的主类是类。在 PyQt 中创建 UI 的所有元素要么是类的子类,要么与类一起使用。QWidgetsQWidgetsQWidgets

您可以在 PyQt 或 Qt 文档中阅读几个小部件类。我们不能在这里一一提及。一些基本的小部件类包括:

QLabel用于显示文本和图像QPushButton用于创建命令按钮QLineEdit用于创建单行文本编辑器QRadioButton用于创建带有文本标签的单选按钮

让我们在“hello world”GUI中添加一个简单的小部件:pushButton

from PyQt5.QtWidgets import QWidget, QApplication, QPushButtonapplication = QApplication([])mainWindow = QWidget()mainWindow.setGeometry(0, 0, 350, 400)mainWindow.setWindowTitle('Button Widget')pushButton = QPushButton(parent=mainWindow, text='Click me')mainWindow.show()application.exec()

运行上面的代码将创建一个类似于下图的窗口。

事件循环

大多数 GUI 工具包都是事件驱动的。PyQt也不例外。事件可能源自用户与应用的交互,例如单击按钮、填充输入文本、单击链接或关闭窗口。事件也可以来自窗口系统或其他源。事件循环负责管理这些事件。

调用该方法将触发事件循环,正如我们在构建“hello world”GUI 时所强调的那样。循环等待事件发生,并在事件发生时做出响应。如果收到事件,它将终止并退出应用程序。.execTerminate

正是通过这种事件-响应功能,您可以使用信号和插槽向 GUI 添加交互性。我们将在下面的部分中了解信号和插槽。

信号和插槽

我们在前面的一节中介绍了如何使用小部件来创建 GUI 的可见组件。通过信号和插槽,您可以为 GUI 添加交互性。我们在“hello world”GUI中添加了一个按钮小部件,但单击该按钮目前不会执行任何操作。

通常,单击按钮应触发操作,例如打开另一个小组件、关闭小组件或登录。您需要信号和插槽来响应此类用户操作或小部件状态的变化。

信号是小部件在发生某些事情时发出的通知。它可以是按钮单击、鼠标移动或文本输入字段中的更改。不同的小部件发出不同的信号。例如,按钮小部件在单击时发出信号。按钮小部件还会发出其他鲜为人知的信号,例如 、 和 信号。要了解特定小部件发出的信号,您需要阅读小部件相应类的文档。clickedpressedreleasedtoggled

插槽是在小部件发出特定信号后调用的函数或方法。几个小部件带有预定义的插槽。但是,您也可以定义插槽来处理感兴趣的信号。

为了说明我们刚刚学到的内容,让我们为按钮小部件添加一个插槽,以便它响应信号运行:clicked

from PyQt5.QtWidgets import QWidget, QApplication, QPushButtonapplication = QApplication([])mainWindow = QWidget()mainWindow.setGeometry(0, 0, 350, 400)mainWindow.setWindowTitle('Slot and Signal')def clickedSlot():    print('The button has been clicked')pushButton = QPushButton(parent=mainWindow, text='Click me')pushButton.clicked.connect(clickedSlot)mainWindow.show()application.exec()

运行上面的代码并单击按钮后,您应该会在终端上看到文本。The button has been clicked

PyQT 布局管理

到目前为止,我们只研究了 PyQt 最基本的组件。在现实世界的应用程序中,您将在同一窗口中处理多个小部件。幸运的是,Qt有几个功能可以在应用程序的UI中管理小部件布局。您可以使用这些功能来描述如何排列微件。每当空间发生变化时,布局都会自动调整小部件的大小和位置。因此,UI 仍然可用。

尽管 PyQt 有几种形式的布局,但在本文中我们将介绍水平、垂直、网格和表单布局。您可以在 PyQt 或 Qt 文档中阅读其他内容。提到的每个布局都有一个相应的内置布局类。这些类是:

QHBoxLayoutQVBoxLayoutQGridLayoutQFormLayout水平布局

您可以使用内置类水平布局小部件,通常是从左到右。它还可以从右到左排列从右到左语言的小部件。QHBoxLayout

在下面的代码中,我修改了“hello world”GUI,以在水平布局中显示五个图像。为了避免重复,我使用循环将图像添加到布局中。在运行此代码之前,请确保文件中有图像:forcat.jpg

from PyQt5.QtGui import QPixmapfrom PyQt5.QtWidgets import (    QLabel,    QWidget,    QApplication,    QHBoxLayout,)application = QApplication([])mainWindow = QWidget()mainWindow.setGeometry(0, 0, 350, 400)mainWindow.setWindowTitle('Horizontal Layout')horizontalLayout = QHBoxLayout()for num in range(6):    label = QLabel()    pixmap = QPixmap('cat.jpg')    label.setPixmap(pixmap)    horizontalLayout.addWidget(label)mainWindow.setLayout(horizontalLayout)mainWindow.show()application.exec()

在 PyQt 中,您可以使用小部件渲染图像。从模块导入类实例后,首先创建类的实例。使用类的方法在标签小部件上设置它,如上面的循环所示。QLabelQPixmapQtGuisetPixmapQLabelfor

您可以在转到下一部分之前使用代码。您可以布置其他小部件(如按钮),而不是布局图像。

上面的代码应该创建一个类似于下图的 GUI。

垂直布局

与从左到右或从右到左水平布局小部件的类不同,该类从上到下垂直放置小部件。QHBoxLayoutQVBoxLayout

下面的代码显示了如何使用该类进行垂直布局管理。它与水平布局非常相似:QVBoxLayout

from PyQt5.QtGui import QPixmapfrom PyQt5.QtWidgets import (    QLabel,    QWidget,    QApplication,    QVBoxLayout,)application = QApplication([])mainWindow = QWidget()mainWindow.setGeometry(0, 0, 350, 400)mainWindow.setWindowTitle('Vertical Layout')verticalLayout = QVBoxLayout()for num in range(6):    label = QLabel()    pixmap = QPixmap('cat.jpg')    label.setPixmap(pixmap)    verticalLayout.addWidget(label)mainWindow.setLayout(verticalLayout)mainWindow.show()application.exec()

运行上面的代码应该创建一个 GUI,其中的图像从上到下排列,类似于下图。

网格布局

网格布局管理涉及在二维网格中布局微件。这是一个方便的内置类,可以做到这一点。在网格布局中,一个项可以占据两个网格。您还可以在网格项中嵌套另一个布局。它使构建更复杂的 GUI 变得更加容易。QGridLayout

您可以使用该方法创建类的实例并向其添加小部件。与前面的部分一样,我将图像循环添加到网格中,以避免在下面的代码中重复。也可以在使用小部件填充网格时跳过网格:QGridLayoutaddWidget

from PyQt5.QtGui import QPixmapfrom PyQt5.QtWidgets import (    QLabel,    QWidget,    QApplication,    QGridLayout,)application = QApplication([])mainWindow = QWidget()mainWindow.setGeometry(0, 0, 350, 400)mainWindow.setWindowTitle('Grid Layout')gridLayout = QGridLayout()for row in range(3):    for col in range(3):        label = QLabel()        pixmap = QPixmap('cat.jpg')        label.setPixmap(pixmap)        gridLayout.addWidget(label, row, col)mainWindow.setLayout(gridLayout)mainWindow.show()application.exec()

由于您要将微件放置在二维网格中,因此在将每个微件添加到布局时,需要指定每个微件的位置。

运行上面的代码后,您的“hello world”GUI 应如下图所示。

表单布局

表单布局主要用于管理输入微件及其关联标签。它由布置为标签字段对的小部件行组成。您需要使用该类在表单布局中排列小部件,如下面的代码所示:QFormLayout

from PyQt5.QtWidgets import (    QGroupBox,    QLabel,    QLineEdit,    QPlainTextEdit,    QRadioButton,    QSpinBox,    QVBoxLayout,    QWidget,    QApplication,    QFormLayout,)application = QApplication([])mainWindow = QWidget()mainWindow.setGeometry(0, 0, 350, 400)mainWindow.setWindowTitle('Form Layout')formLayout = QFormLayout()nameLabel = QLabel('Name')nameField = QLineEdit()ageLabel = QLabel('Age')ageField = QSpinBox()ageField.setMinimum(0)ageField.setMaximum(130)sexLabel = QLabel('Sex')sexGroup = QGroupBox()verticalLayout = QVBoxLayout()for sex in ['Male', 'Female', 'Other']:    radioButton = QRadioButton(sex)    verticalLayout.addWidget(radioButton)sexGroup.setLayout(verticalLayout)commentLabel = QLabel('Comments')commentField = QPlainTextEdit()formLayout.addRow(nameLabel, nameField)formLayout.addRow(ageLabel, ageField)formLayout.addRow(sexLabel, sexGroup)formLayout.addRow(commentLabel, commentField)mainWindow.setLayout(formLayout)mainWindow.show()application.exec()

运行上面的代码以查看类似于下图的 GUI。您可以看到小部件的标签字段对。每行都有一个标签微件和右侧的相应字段微件。

上面提到的布局绝不是详尽无遗的。您可以在 PyQt 或 Qt 文档中阅读其他形式的布局。

主窗口框架

使用 PyQt,您可以使用任意小部件来创建主窗口;这就是我们为前面部分中的插图所做的,以使事情变得简单易懂。但是,这不是您在实际应用程序中所做的。PyQt 附带了用于管理应用程序主窗口的类。QMainWindow

该类提供用于添加小部件(如菜单栏、工具箱和状态栏)的布局。通常的做法是创建类的子类并将其用作主窗口。这就是我们要做的。QMainWindowQMainWindow

下面是“hello world”GUI的重构代码:

from PyQt5.QtWidgets import QMainWindow, QApplicationclass MainWindow(QMainWindow):    def __init__(self, parent=None):        super().__init__(parent)        self.setWindowTitle('Hello Wordl')        self.setGeometry(0, 0, 350, 400)if (__name__ == '__main__'):    application = QApplication([])    mainWindow = MainWindow()    mainWindow.show()    application.exec()

你会注意到我们的类是如何从类继承的。当您运行上面的代码时,它创建的窗口将与我们的第一个“hello world”GUI 相同。从现在开始,我们将始终创建类的子类。MainWindowQMainWindowQMainWindow

如何创建菜单栏

菜单是大多数 GUI 应用程序的特征。桌面 GUI 通常在主窗口的顶部有菜单。某些下拉菜单具有在悬停时打开的子菜单。下图显示了桌面 GUI 上的典型菜单的外观。

如上一节所述,该类提供了一个布局,用于将菜单栏添加到开箱即用的 GUI。若要创建菜单栏,需要使用该方法。QMainWindowmenuBar

下面是用于在上图中创建下拉菜单的代码。我使用该类来创建操作,并将它们添加到相应的菜单中以创建下拉菜单:QAction

from PyQt5.QtWidgets import QMainWindow, QApplication, QActionclass MainWindow(QMainWindow):    def __init__(self, parent=None):        super().__init__(parent)        self.setWindowTitle('Dropdown Menu')        self.setGeometry(0, 0, 350, 400)        self.addMenu()    def addMenu(self):        # Create menu bar        menuBar = self.menuBar()        # Add menu items        fileMenu = menuBar.addMenu('File')        helpMenu = menuBar.addMenu('Help')        # Create actions        visitWebsiteAction = QAction('Visit Our Website', self)        fileBugReportAction = QAction('File a Bug Report', self)        # Add dropdown menu items on the Help menu        helpMenu.addAction(visitWebsiteAction)        helpMenu.addAction(fileBugReportAction)        # Add 'Follow Us' dropdown menu item on the Help menu        followUs = helpMenu.addMenu('Follow Us')        # Social media actions        twitterAction = QAction('Twitter', self)        githubAction = QAction('GitHub', self)        # Add actions        followUs.addAction(twitterAction)        followUs.addAction(githubAction)if (__name__ == '__main__'):    application = QApplication([])    mainWindow = MainWindow()    mainWindow.show()    application.exec()
使用 PyQt 构建标准 GUI

希望上述部分已经向您介绍了 PyQt 的基础知识。现在,让我们通过构建标准 GUI 来使用我们刚刚获得的知识。

下图显示了密码管理应用程序的桌面版本的登录屏幕。它有一个菜单栏和一个密码字段。在前面的部分中,我们已经查看了 GUI 中的大多数小部件。但是,我将很快简要解释一些方法。

我只关注基础知识,保持简单。如果您有兴趣,可以通过添加更多功能和交互性来进一步推动自己。

下面是上述 GUI 的相应代码。我已经在大多数部分留下了评论,以解释正在发生的事情。我敦促您在阅读我的解释之前通读代码:

from PyQt5.QtWidgets import (QAction, QApplication, QFormLayout, QGroupBox,                             QLabel, QPushButton, QVBoxLayout, QWidget,                             QMainWindow, QLineEdit)from PyQt5.QtCore import Qtfrom PyQt5.QtGui import QPixmapclass MainWindow(QMainWindow):    def __init__(self, parent=None):        super().__init__(parent)        self.createUI()        self.createActions()        self.creatMenu()    def createUI(self):        # Create window        self.setWindowTitle('Password Manager')        self.resize(800, 500)        self.setMinimumSize(500, 450)        # Create central widget and layout        self._centralWidget = QWidget()        self._verticalLayout = QVBoxLayout()        self._centralWidget.setLayout(self._verticalLayout)        # Set central widget        self.setCentralWidget(self._centralWidget)        # Vertically center widgets        self._verticalLayout.addStretch(1)        # Add lock image        self.addLockImage()        self.addText()        self.addInputText()        # Vertically center widgets        self._verticalLayout.addStretch(1)        # Add Copyright        self.addCopyRight()    def addLockImage(self):        imageLabel = QLabel()        pixmap = QPixmap('lock.png')        imageLabel.setPixmap(pixmap)        self._verticalLayout.addWidget(imageLabel, alignment=Qt.AlignCenter)    def addText(self):        messageLabel = QLabel(            'Hi there . Your vault is locked. Verify your master password to continue.'        )        messageLabel.setAlignment(Qt.AlignCenter)        messageLabel.setFixedWidth(350)        messageLabel.setMinimumHeight(50)        messageLabel.setWordWrap(True)        self._verticalLayout.addWidget(messageLabel, alignment=Qt.AlignCenter)    def addCopyRight(self):        copyRight = QLabel(            'Copyright © <a href=";>LogRocket</a> 2021')        copyRight.setOpenExternalLinks(True)        self._verticalLayout.addWidget(copyRight, alignment=Qt.AlignCenter)    def addInputText(self):        groupBox = QGroupBox()        groupBox.setFixedWidth(350)        formLayout = QFormLayout()        passwordLabel = QLabel('Master Password')        passwordField = QLineEdit()        passwordField.setTextMargins(3, 0, 3, 0)        passwordField.setMinimumWidth(200)        passwordField.setMaximumWidth(300)        passwordField.setEchoMode(QLineEdit.Password)        passwordField.setClearButtonEnabled(True)        submitLabel = QLabel('Open Your Vault')        submitField = QPushButton()        formLayout.addRow(passwordLabel, passwordField)        formLayout.addRow(submitLabel, submitField)        groupBox.setLayout(formLayout)        self._verticalLayout.addWidget(groupBox, alignment=Qt.AlignCenter)    def creatMenu(self):        # Create menu bar        menuBar = self.menuBar()        # Add menu items        fileMenu = menuBar.addMenu('File')        editMenu = menuBar.addMenu('Edit')        accountMenu = menuBar.addMenu('Account')        helpMenu = menuBar.addMenu('Help')        # Add sub-items under Help menu item        helpMenu.addAction(self.sendEmailAction)        helpMenu.addAction(self.visitWebsiteAction)        helpMenu.addAction(self.fileBugReportAction)        # Add horizontal line        helpMenu.addSeparator()        # Add 'Follow Us' sub-item under Help menu item        # Use addMenu method because it contains sub-items        followUs = helpMenu.addMenu('Follow Us')        followUs.addAction(self.twitterAction)        followUs.addAction(self.facebookAction)        followUs.addAction(self.githubAction)    def createActions(self):        # Help menu actions        self.sendEmailAction = QAction('Email Us', self)        self.visitWebsiteAction = QAction('Visit Our Website', self)        self.fileBugReportAction = QAction('File a Bug Report', self)        # Social media actions        self.twitterAction = QAction('Twitter', self)        self.facebookAction = QAction('Facebook', self)        self.githubAction = QAction('GitHub', self)if (__name__ == '__main__'):    application = QApplication([])    mainWindow = MainWindow()    mainWindow.show()    application.exec()

在上面的代码中,我声明了创建 GUI 的方法。我已经提取了用于创建其他小部件的功能以分离方法。在前面的部分中,我们遇到了构成 UI 的大多数小部件,我在代码中添加了注释来解释正在发生的事情。因此,我不会在这里解释所有这些。但是,我将讨论UI的组织方式。createUI

GUI 由垂直布局中的四个小部件组成。我使用该方法在垂直布局的开头添加了一个可拉伸空间。同样,在分组框之后还有另一个可拉伸空间。可拉伸空间有助于将版权文本置换到 GUI 的底部,并使其余小部件垂直居中。addStretch

前面的部分介绍了以编程方式构建 GUI 应用的基础知识。有一个替代的拖放界面用于构建GUI,称为Qt Designer。它将显着提高您的生产力。有关更多信息,您可以阅读Qt设计师手册。

结论

如果你想使用Python开发跨平台的GUI应用程序,PyQt是一个方便的工具包。您可以使用各种内置类来创建小部件,然后使用信号和插槽添加交互性。将其与Qt Designer一起使用可以显着减少开发时间并提高生产力。

希望这篇文章对您有所帮助。我们在这里介绍的只是基础知识,PyQt 有大量的类和方法。尽管如此,我希望它能为您提供足够的背景知识来阅读文档并开始使用 PyQt。

不幸的是,在撰写本文时,PyQt5 和 PyQt6 文档中有很多缺失的部分。因此,在没有其他资源的情况下使用 PyQt 文档可能不是很有帮助。您需要同时使用 PyQt 和 Qt 文档。

但是,请注意,Qt文档是面向C++的。您还可以将文档用于早期版本的 PyQt(如 PyQt4),而不是最新版本(如 PyQt5 或 PyQt6)。API 的某些部分没有太大变化。

标签: #pythonqtdesigner