Pyqt5 简明教程

PyQt5 - Quick Guide

PyQt5 - Introduction

PyQt 是 GUI 窗口小部件工具包。它是 Qt 的 Python 接口,它是最强大、最流行的跨平台 GUI 库之一。PyQt 由 RiverBank Computing Ltd. 开发。可以从其官方网站 − riverbankcomputing.com 下载 PyQt 的最新版本

PyQt API 是一套包含大量类和函数的模块。其中 QtCore 模块包含用于处理文件、目录等的非 GUI 功能, QtGui 模块包含所有图形控制。此外,还有用于处理 XML (QtXml) 、SVG (QtSvg) 和 SQL (QtSql) 等的模块。

以下是常用模块的列表 −

  1. QtCore − 其他模块使用的核心非 GUI 类

  2. QtGui − 图形用户界面组件

  3. QtMultimedia − 低级多媒体编程类

  4. QtNetwork − 网络编程类

  5. QtOpenGL − OpenGL 支持类

  6. QtScript − Qt 脚本评估类

  7. QtSql − 使用 SQL 集成数据库的类

  8. QtSvg − 用于显示 SVG 文件内容的类

  9. QtWebKit − 用于呈现和编辑 HTML 的类

  10. QtXml − XML 处理类

  11. QtWidgets − 创建传统桌面风格 UI 的类

  12. QtDesigner − Qt Designer 扩展类

Supporting Environments

PyQt 与所有流行的操作系统兼容,包括 Windows、Linux 和 Mac OS。它采用双重许可证,既有 GPL 也提供商业许可证。最新稳定版本是 PyQt5-5.13.2.

Windows

提供了与 Python 3.5 或更高版本兼容的 32 位或 64 位架构的文件轮。推荐使用 PIP 实用程序进行安装 −

pip3 install PyQt5

要在 Linux/macOS 上从源代码 www.riverbankcomputing.com/static/Downloads/PyQt5 构建 PyQt5,请使用以下命令 −

pip3 install pyqt5-tools

您还可以在 Linux/macOS 上从 www.riverbankcomputing.com/static/Downloads/PyQt5 构建 PyQt5。

PyQt5 - What’s New

PyQt5 API 不会自动与早期版本兼容。因此,涉及 PyQt4 模块的 Python 代码应通过进行相关更改手动升级。在本章中,列出了 PyQt4 和 PyQt5 之间的差异。

v2.6 早期版本的 Python 不支持 PyQt5。

PyQt5 不支持 QObject 类的 connect() 方法用于信号与槽之间的连接。因此,不能再实现用法 −

QObject.connect(widget, QtCore.SIGNAL(‘signalname’), slot_function)

仅定义以下语法 −

widget.signal.connect(slot_function)

早期 QtGui 模块中定义的类已分布在 QtGui, QtPrintSupportQtWidgets 模块中。

在新 QFileDialog 类的 getOpenFileNameAndFilter() 方法中, getOpenFileName(), getOpenFileNamesAndFilter()getOpenFileNames()getSaveFileNameAndFilter()getSaveFileName() 替换。旧这些方法的签名也已发生更改。

PyQt5 无法定义一个从多个 Qt 类进行子类化的类。

pyuic5 实用程序(用于从 Designer 的 XML 文件生成 Python 代码)不支持 --pyqt3-wrapper 标志。

pyrcc5 不支持 -py2 和 -py3 标志。pyrcc5 的输出与 v2.6 及以后版本的所有 Python 版本均兼容。

PyQt5 始终自动调用 sip.setdestroyonexit() 并调用它拥有的所有封装实例的 C++ 析构函数。

PyQt5 - Hello World

使用 PyQt 创建简单的 GUI 应用程序涉及以下步骤 −

  1. 从 PyQt5 包导入 QtCore、QtGui 和 QtWidgets 模块。

  2. 创建 QApplication 类的应用程序对象。

  3. QWidget 对象创建顶层窗口。在其中添加 QLabel 对象。

  4. 将标签标题设为“你好,世界”。

  5. 通过 setGeometry() 方法定义窗口的大小和位置。

  6. 通过 app.exec_() 方法进入应用程序的主循环。

以下是 PyQt 中执行 Hello World 程序的代码:

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
def window():
   app = QApplication(sys.argv)
   w = QWidget()
   b = QLabel(w)
   b.setText("Hello World!")
   w.setGeometry(100,100,200,50)
   b.move(50,20)
   w.setWindowTitle("PyQt5")
   w.show()
   sys.exit(app.exec_())
if __name__ == '__main__':
   window()

上述代码生成以下输出 -

hello world

还可以为上述代码开发面向对象的解决方案。

  1. 从 PyQt5 包导入 QtCore、QtGui 和 QtWidgets 模块。

  2. 创建 QApplication 类的应用程序对象。

  3. 基于 QWidget 类声明窗口类

  4. 添加 QLabel 对象并将标签标题设为“你好,世界”。

  5. 通过 setGeometry() 方法定义窗口的大小和位置。

  6. 通过 app.exec_() 方法进入应用程序的主循环。

以下是面向对象解决方案的完整代码:

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class window(QWidget):
   def __init__(self, parent = None):
      super(window, self).__init__(parent)
      self.resize(200,50)
      self.setWindowTitle("PyQt5")
      self.label = QLabel(self)
      self.label.setText("Hello World")
      font = QFont()
      font.setFamily("Arial")
      font.setPointSize(16)
      self.label.setFont(font)
      self.label.move(50,20)
def main():
   app = QApplication(sys.argv)
   ex = window()
   ex.show()
   sys.exit(app.exec_())
if __name__ == '__main__':
   main()
hello worlds

PyQt5 - Major Classes

PyQt API 是一个包含大量类和方法的集合。这些类在 20 多个模块中进行定义。

以下是经常使用的一些模块 −

Sr.No.

Modules & Description

1

其他模块使用的 QtCore Core 非 GUI 类

2

QtGui Graphical user interface components

3

用于低级多媒体编程的 QtMultimedia

4

QtNetwork Classes for network programming

5

QtOpenGL OpenGL support classes

6

用于评估 Qt 脚本的 QtScript

7

用于使用 SQL 进行数据库集成的 QtSql

8

用于显示 SVG 文件内容的 QtSvg

9

用于渲染和编辑 HTML 的 QtWebKit

10

QtXml Classes for handling XML

11

QtWidgets 用于创建经典桌面风格 UI 的类。

12

用于扩展 Qt Designer 的 QtDesigner

13

QtAssistant Support for online help

PyQt5 开发工具是一系列用于 Qt 开发的有用实用程序。以下是此类实用程序的精选列表 −

Sr.No.

Tool Name & Description

1

assistant Qt Assistant documentation tool

2

pyqt5designer Qt Designer GUI 布局工具

3

linguist Qt Linguist translation tool

4

lrelease 将 ts 文件编译为 qm 文件

5

pylupdate5 提取转换字符串,并生成或更新 ts 文件

6

qmake Qt software build tool

7

pyqt5qmlscene QML file viewer

8

pyqmlviewer QML file viewer

9

pyrcc5 Qt resource file compiler

10

pyuic5 用于根据 ui 文件生成代码的 Qt 用户界面编译器

11

pyqmltestrunner 在 QML 代码上运行单元测试

12

qdbus 用于列出 D-Bus 服务的命令行工具

13

QDoc 软件项目的文档生成器。

14

Qhelpgenerator 生成和查看 Qt 帮助文件。

15

qmlimportscanner 解析和报告 QML 导入

PyQt API 包含 400 多个类。 QObject 类位于类层次结构的顶部。它是所有 Qt 对象的基类。此外, QPaintDevice 类是所有可绘制对象的基类。

QApplication 类管理 GUI 应用程序的主设置和控制流。它包含主事件循环,在该循环中处理和分派由窗口元素和其他源生成的事件。它还处理系统范围和应用程序范围的设置。

QWidget 类派生自 QObject 和 QPaintDevice 类,是所有用户界面对象的基类。 QDialogQFrame 类也派生自 QWidget 类。它们有自己的子类系统。

以下是一些常用的控件精选列表

Sr.No.

Widgets & Description

1

QLabel 用于显示文本或图像

2

QLineEdit 允许用户输入一行文本

3

QTextEdit 允许用户输入多行文本

4

QPushButton 用于调用动作的命令按钮

5

QRadioButton 允许从多个选项中选择一个

6

QCheckBox 允许选择多个选项

7

QSpinBox 允许增加/减少整数值

8

QScrollBar 允许访问超出显示孔径的小部件的内容

9

QSlider 允许线性更改绑定值

10

QComboBox 提供可供选择的项目下拉列表

11

QMenuBar 容纳 QMenu 对象的水平栏

12

QStatusBar 通常位于 QMainWindow 底部,提供状态信息。

13

QToolBar 通常位于 QMainWindow 顶部或悬浮。包含动作按钮

14

QListView 在 ListMode 或 IconMode 中提供项目可选择列表

15

QPixmap 用于在 QLabel 或 QPushButton 对象上显示的屏幕外图像表现形式

16

QDialog 可以向父窗口返回信息的模态或无模态窗口

典型的基于 GUI 的应用程序的顶级窗口由 QMainWindow 小部件对象创建。上面列出的一些小部件在这个主窗口中占据各自指定的位置,而其他一些小部件则使用各种布局管理器放置在中央小部件区域中。

下图显示了 QMainWindow 框架 -

qmainwindow

PyQt5 - Using Qt Designer

PyQt 安装程序附带了一个名为 Qt Designer 的 GUI 构建工具。利用其简单的拖放界面,可以快速构建 GUI 界面而无需编写代码。然而,它不是像 Visual Studio 这样的 IDE。因此,Qt Designer 没有调试和构建应用程序的功能。

启动 Qt Designer 应用程序,该应用程序是一个开发工具的一部分,安装在虚拟环境的脚本文件夹中。

virtual environment

通过选择 File → New 菜单开始设计 GUI 界面。

new menu

然后,您可以从左侧窗格中的小部件框中拖放所需の小部件。您还可以将值分配给布置在窗体上的小部件的属性。

widget

设计的表单保存为 demo.ui。该 ui 文件包含小部件及其在设计中的属性的 XML 表示。此设计通过使用 pyuic5 命令行实用程序转换为等效 Python。该实用程序是 Qt 工具包的 uic 模块的一个包装器。pyuic5 的用法如下 −

pyuic5 -x demo.ui -o demo.py

在上面的命令中,-x 交换机向生成的 Python 脚本(从 XML)添加少量的附加代码,使其成为可独立执行的独立应用程序。

if __name__ == "__main__":
   import sys
   app = QtGui.QApplication(sys.argv)
   Dialog = QtGui.QDialog()
   ui = Ui_Dialog()
   ui.setupUi(Dialog)
   Dialog.show()
   sys.exit(app.exec_())

执行结果 Python 脚本以显示以下对话框 −

python demo.py
dialog box

用户可以在输入字段中输入数据,但单击“添加”按钮不会生成任何操作,因为它不与任何函数关联。对用户生成的响应作出反应被称为 event handling

PyQt5 - Signals & Slots

与按顺序执行的控制台模式应用程序不同,基于 GUI 的应用程序是事件驱动的。函数或方法会执行响应用户的操作,例如单击按钮、从集合中选择一个项目,或鼠标单击等,称为 events

用于构建 GUI 界面并担任这些事件来源的控件。每个 PyQt 控件都派生自 QObject 类,设计为针对一个或多个事件发出 ‘signal’ 。信号本身不执行任何操作。相反,它“连接”到 ‘slot’ 。槽可以是任何 callable Python function

Using Qt Designer’s Signal/Slot Editor

先使用 LineEdit 控件和 PushButton 设计一个简单的窗体。

slot editor

期望在按下按钮时擦除文本框中的内容。QLineEdit 控件为此提供了一个 clear() 方法。因此,按钮的 clicked 信号要连接到文本框的 clear() 方法。

首先,从 Edit 菜单选择 Edit signals/slots(或按 F4)。然后用鼠标高亮显示按钮,并拖动光标指向文本框

cursor

当释放鼠标时,将显示一个对话框,其中显示按钮的信号和槽的方法。选择 clicked 信号和 clear() 方法

clear method

右下角的 Signal/Slot Editor 窗口将显示结果 −

editor window

按以下代码所示从 ui 文件中保存 ui 和构建 Python 代码 −

pyuic5 -x signalslot.ui -o signalslot.py

生成的 Python 代码将通过以下语句在信号和槽之间建立连接 −

self.pushButton.clicked.connect(self.lineEdit.clear)

运行 signalslot.py,然后在 LineEdit 中输入一些文本。如果按下按钮,文本将被清除。

Building Signal-slot Connection

除了使用 Designer,你还可以按照以下语法直接建立信号-槽连接 −

widget.signal.connect(slot_function)

假设在按下按钮时需要调用一个函数。在这里,clicked 信号要连接到一个可调用函数。它可以通过以下任何技术实现 −

button.clicked.connect(slot_function)

Example

在以下示例中,两个 QPushButton 对象(b1 和 b2)添加到 QDialog 窗口中。我们希望分别在单击 b1 和 b2 时调用函数 b1_clicked() 和 b2_clicked()。

当单击 b1 时,clicked() 信号连接到 b1_clicked() 函数 −

b1.clicked.connect(b1_clicked())

当单击 b2 时,clicked() 信号连接到 b2_clicked() 函数。

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def window():
   app = QApplication(sys.argv)
   win = QDialog()
   b1 = QPushButton(win)
   b1.setText("Button1")
   b1.move(50,20)
   b1.clicked.connect(b1_clicked)

   b2 = QPushButton(win)
   b2.setText("Button2")
   b2.move(50,50)
   b2.clicked.connect(b2_clicked)

   win.setGeometry(100,100,200,100)

   win.setWindowTitle("PyQt5")
   win.show()
   sys.exit(app.exec_())

def b1_clicked():
   print ("Button 1 clicked")

def b2_clicked():
   print ("Button 2 clicked")

if __name__ == '__main__':
   window()

上述代码生成以下输出 -

pushbutton

Output

Button 1 clicked
Button 2 clicked

PyQt5 - Layout Management

可以通过指定 GUI 小组件绝对坐标来将其放置在容器窗口中,坐标以像素为单位进行测量。坐标相对于 setGeometry() 方法定义的窗口维度。

setGeometry() syntax

QWidget.setGeometry(xpos, ypos, width, height)

在下面的代码片段中,300 乘以 200 像素维度的主窗口显示在监视器上的位置 (10, 10)。

import sys
from PyQt4 import QtGui

def window():
   app = QtGui.QApplication(sys.argv)
   w = QtGui.QWidget()

   b = QtGui.QPushButton(w)
   b.setText("Hello World!")
   b.move(50,20)

   w.setGeometry(10,10,300,200)
   w.setWindowTitle(“PyQt”)
   w.show()
   sys.exit(app.exec_())

if __name__ == '__main__':
   window()

在窗口中添加了一个 PushButton 小组件,并将其放置在距离窗口左上角 50 像素的右侧和 20 像素的下方。

但是,这种绝对定位由于以下原因而不适合:

  1. 即使调整了窗口的大小,小组件的位置也不会改变。

  2. 在具有不同分辨率的不同显示设备上,外观可能不统一。

  3. 布局中的修改比较困难,因为它可能需要重新设计整个表单。

original resized window

PyQt API 提供布局类,可以更优雅地管理容器内小组件的位置。相对于绝对定位,布局管理器的优点是 -

  1. 窗口中的小组件自动调整大小。

  2. 确保在不同分辨率的显示设备上一致的外观。

  3. 添加或删除小组件的动态性无需重新设计。

Qt 工具包定义了可与 Qt Designer 实用程序一起使用的各种布局。

display class

以下是我们将在本章中依次讨论的类列表。

Sr.No.

Classes & Description

1

QBoxLayout QBoxLayout 类垂直或水平排列小部件。它的派生类是 QVBoxLayout(用于垂直排列小部件)和 QHBoxLayout(用于水平排列小部件)。

2

QGridLayout A GridLayout 类对象显示为按行和列排列的单元格网格。该类包含 addWidget() 方法。可以通过指定单元格的行和列数来添加任何小部件。

3

QFormLayout QFormLayout 是创建两栏表单的一种便捷方式,其中每行都包含一个与标签关联的输入字段。按照惯例,左栏包含标签,右栏包含输入字段。

PyQt5 - Basic Widgets

以下是我们将在本章中依次讨论的小组件列表。

Sr.No

Widgets & Description

1

QLabel A QLabel 对象用作放置不可编辑文本或图像,或动态 GIF 电影的占位符。它还可以用作其他窗口小部件的助记键。

2

QLineEdit QLineEdit 对象是最常用的输入字段。它提供了一个框,可以在其中输入一行文本。为了输入多行文本,需要 QTextEdit 对象。

3

QPushButton 在 PyQt API 中,QPushButton 类对象表示一个按钮,当单击该按钮时,可以对其进行编程以调用特定函数。

4

QRadioButton A QRadioButton 类对象表示具有文本标签的可选择按钮。用户可以选择表单上提供的众多选项之一。此类派生自 QAbstractButton 类。

5

QCheckBox 当将 QCheckBox 对象添加到父窗口时,文本标签前会出现一个矩形框。就像 QRadioButton 一样,它也是一个可选择按钮。

6

QComboBox A QComboBox 对象显示 items 的下拉列表以供选择。它在表单上占用最少的屏幕空间来只显示当前选定的项目。

7

QSpinBox A QSpinBox 对象向用户展示一个带有整数的文本框,其右侧为向上/向下按钮。

8

QSlider Widget & Signal QSlider 类对象向用户展示一条槽,可以在其上移动一个句柄。它是一个经典窗口小部件,用于控制有界值。

9

QMenuBar, QMenu & QAction 一个水平 QMenuBar 就在 QMainWindow 对象的标题栏下方,用于显示 QMenu 对象。

10

QToolBar A QToolBar 窗口小部件是一个可移动面板,由文本按钮、带图标的按钮或其他窗口小部件组成。

11

QInputDialog 这是一个预配置的对话框,其中有文本字段和两个按钮,确定和取消。父窗口在用户单击确定按钮或按 Enter 键后收集文本框中的输入。

12

QFontDialog 另一个常用的对话框,一个字体选择器窗口小部件是 QDialog 类的视觉外观。此对话框的结果是 Qfont 对象,可以被父窗口使用。

13

QFileDialog 这个窗口小部件是一个文件选择器对话框。它使用户能够浏览文件系统并选择要打开或保存的文件。可以通过静态函数或通过在对话框对象上调用 exec_() 函数来调用该对话框。

14

QTab 如果一个表单具有太多字段不能同时显示,则可以将它们排列在制表窗口小部件的每个选项卡下放置的不同页面中。QTabWidget 提供一个选项卡栏和一个页面区域。

15

QStacked QStackedWidget 的功能类似于 QTabWidget。它还有助于有效利用窗口的客户端区域。

16

QSplitter 这是另一个高级布局管理器,它允许通过拖动它们之间的边界来动态地更改子窗口小部件的大小。Splitter 控件提供了一个句柄,可以将其拖动以调整控件大小。

17

QDock 可停靠窗口是子窗口,它能够保持浮动状态,或在指定位置附着到主窗口。QMainWindow 类的主窗口对象包含了专门用于可停靠窗口的区域。

18

QStatusBar 主窗口对象在底部保留一条水平栏作为状态栏。该栏用于显示永久或上下文相关的状态信息。

19

QList QListWidget 类基于项目的接口,用于从列表中添加或删除项目。列表中的每个项目都是一个 QListWidgetItem 对象。可以将 ListWidget 设置为多选。

20

QScrollBar 滚动条控件使用户能够访问可视区域之外的文档部分。它可以提供当前位置的可视指示。

21

QCalendar QCalendar 小部件是一个有用的日期选择器控件。它提供基于月份的视图。用户可以使用鼠标或键盘来选择日期,默认日期为当天日期。

PyQt5 - QDialog Class

QDialog 小部件提供顶层窗口,主要用于收集用户的响应。可以将其配置为 Modal (它会阻止其父窗口)或 Modeless (可以绕过该对话框窗口)。

PyQt API 具有许多预配置的 Dialog 小部件,例如 InputDialog、FileDialog、FontDialog 等。

Example

在以下示例中, WindowModality 对话框窗口的属性决定它是模态还是非模态。可以将对话框上的任意一个按钮设为默认按钮。当用户按下 Esc 键时, QDialog.reject() 方法将丢弃该对话框。

当顶层 QWidget 窗口上的 PushButton 被单击时,会生成一个 Dialog 窗口。Dialog 框的标题栏上没有最小化和最大化控件。

用户无法将此对话框框降级到背景中,因为其 WindowModality 已设为 ApplicationModal

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def window():
   app = QApplication(sys.argv)
   w = QWidget()
   btn = QPushButton(w)
   btn.setText("Hello World!")
   btn.move(100,50)
   btn.clicked.connect(showdialog)
   w.setWindowTitle("PyQt Dialog demo")
   w.show()
   sys.exit(app.exec_())

def showdialog():
   dlg = QDialog()
   b1 = QPushButton("ok",dlg)
   b1.move(50,50)
   dlg.setWindowTitle("Dialog") 9. PyQt5 — QDialog Class
   dlg.setWindowModality(Qt.ApplicationModal)
   dlg.exec_()

if __name__ == '__main__':
   window()

上述代码会生成以下输出。单击主窗口中的按钮,弹出对话框框:

qdialog class output

PyQt5 - QMessageBox

QMessageBox 是一个常用的模态对话框,用于显示一些信息消息,还可以让用户通过点击其上的任意一个标准按钮进行响应。每个标准按钮都有一个预定义的标题、一个角色,并返回一个预定义的十六进制数。

与 QMessageBox 类相关的重要方法和枚举在下表中给出−

Sr.No.

Methods & Description

1

setIcon() 显示与消息严重性相对应的预定义图标QuestionInformationWarningCritical

2

setText() 设置要显示的主消息的文本

3

setInformativeText() Displays additional information

4

setDetailText() 对话框显示一个“详细信息”按钮。这个文本会在此按钮被点击时出现

5

setTitle() 显示对话框的自定义标题

6

setStandardButtons() 要显示的标准按钮列表。每个按钮都与以下相关联QMessageBox.Ok 0x00000400QMessageBox.Open 0x00002000QMessageBox.Save 0x00000800QMessageBox.Cancel 0x00400000QMessageBox.Close 0x00200000QMessageBox.Yes 0x00004000QMessageBox.No 0x00010000QMessageBox.Abort 0x00040000QMessageBox.Retry 0x00080000QMessageBox.Ignore 0x00100000

7

setDefaultButton() 将按钮设为默认按钮。如果按下 Enter,它会发出 clicked 信号

8

setEscapeButton() 将按钮设置为在按下 Escape 键时视为已单击

Example

在以下示例中,点击顶层窗口上的按钮信号,连接的函数将显示消息框对话框。

msg = QMessageBox()
msg.setIcon(QMessageBox.Information)
msg.setText("This is a message box")
msg.setInformativeText("This is additional information")
msg.setWindowTitle("MessageBox demo")
msg.setDetailedText("The details are as follows:")

setStandardButton() 函数将显示所需的按钮。

msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)

buttonClicked() 信号连接到槽函数,该函数标识信号源的标题。

msg.buttonClicked.connect(msgbtn)

示例的完整代码如下 −

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def window():
   app = QApplication(sys.argv)
   w = QWidget()
   b = QPushButton(w)
   b.setText("Show message!")

   b.move(100,50)
   b.clicked.connect(showdialog)
   w.setWindowTitle("PyQt MessageBox demo")
   w.show()
   sys.exit(app.exec_())

def showdialog():
   msg = QMessageBox()
   msg.setIcon(QMessageBox.Information)

   msg.setText("This is a message box")
   msg.setInformativeText("This is additional information")
   msg.setWindowTitle("MessageBox demo")
   msg.setDetailedText("The details are as follows:")
   msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
   msg.buttonClicked.connect(msgbtn)

   retval = msg.exec_()

def msgbtn(i):
   print ("Button pressed is:",i.text())

if __name__ == '__main__':
   window()

上述代码会生成以下输出。单击主窗口的按钮时弹出消息框:

qmessagebox output

如果您单击 MessageBox 上的确定或取消按钮,将在控制台上生成以下输出:

Button pressed is: OK
Button pressed is: Cancel

PyQt5 - Multiple Document Interface

典型的 GUI 应用程序可能有多个窗口。标签式和小部件可随时激活一个这样的窗口。但是,很多时候此方法可能没有用,因为其他窗口的视图被隐藏了。

同时显示多个窗口的一种方法是将它们创建为独立的窗口。称为 SDI (single Document Interface) 。由于每个窗口可能有自己的菜单系统、工具栏等,所以需要更多的内存资源。

MDI (Multiple Document Interface) 应用程序消耗的内存资源更少。子窗口会放在主容器内,彼此相关。该容器窗口小部件称为 QMdiArea

QMdiArea 小部件通常占用 QMainWondow 对象的中央小部件。此区域内的子窗口是 QMdiSubWindow 类实例。可以将任何 QWidget 设置为 subWindow 对象的内部小部件。MDI 区域内的子窗口可以以层叠或平铺方式进行排列。

下表列出了 QMdiArea 类和 QMdiSubWindow 类的重要方法 -

Sr.No.

Methods & Description

1

addSubWindow() 将窗口小部件添加为 MDI 区域中的一个新子窗口

2

removeSubWindow() 移除作为子窗口的内部窗口窗口小部件

3

setActiveSubWindow() Activates a subwindow

4

cascadeSubWindows() 以级联方式排列 MDiArea 中的子窗口

5

tileSubWindows() 以平铺方式排列 MDiArea 中的子窗口

6

closeActiveSubWindow() Closes the active subwindow

7

subWindowList() 返回 MDI 区域中的子窗口列表

8

setWidget() 设置一个 QWidget 作为 QMdiSubwindow 实例的内部窗口小部件

QMdiArea 对象发出 subWindowActivated() 信号,而 QMdisubWindow 对象发出 windowStateChanged() 信号。

Example

在以下示例中,包含 QMainWindow 的顶级窗口有一个菜单和 MdiArea。

self.mdi = QMdiArea()
self.setCentralWidget(self.mdi)
bar = self.menuBar()
file = bar.addMenu("File")

file.addAction("New")
file.addAction("cascade")
file.addAction("Tiled")

菜单的 Triggered() 信号连接到 windowaction() 函数。

file.triggered[QAction].connect(self.windowaction)

菜单的新操作向 MDI 区域中添加子窗口,其标题有一个递增的数字。

MainWindow.count = MainWindow.count+1
sub = QMdiSubWindow()
sub.setWidget(QTextEdit())
sub.setWindowTitle("subwindow"+str(MainWindow.count))
self.mdi.addSubWindow(sub)
sub.show()

菜单的级联和平铺按钮分别以级联和平铺方式排列当前显示的子窗口。

完整代码如下所示:

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class MainWindow(QMainWindow):
   count = 0

   def __init__(self, parent = None):
      super(MainWindow, self).__init__(parent)
      self.mdi = QMdiArea()
      self.setCentralWidget(self.mdi)
      bar = self.menuBar()

      file = bar.addMenu("File")
      file.addAction("New")
      file.addAction("cascade")
      file.addAction("Tiled")
      file.triggered[QAction].connect(self.windowaction)
      self.setWindowTitle("MDI demo")

   def windowaction(self, q):
      print ("triggered")

      if q.text() == "New":
         MainWindow.count = MainWindow.count+1
         sub = QMdiSubWindow()
         sub.setWidget(QTextEdit())
         sub.setWindowTitle("subwindow"+str(MainWindow.count))
         self.mdi.addSubWindow(sub)
         sub.show()

      if q.text() == "cascade":
         self.mdi.cascadeSubWindows()

      if q.text() == "Tiled":
         self.mdi.tileSubWindows()

def main():
   app = QApplication(sys.argv)
   ex = MainWindow()
   ex.show()
   sys.exit(app.exec_())

if __name__ == '__main__':
   main()

运行以上代码,就会以层叠和平铺形式获得三个窗口−

multiple document interface output
multiple document interface outputs
multiple document interface

PyQt5 - Drag and Drop

提供 drag and drop 对用户来说非常直观。它存在于许多桌面应用程序中,用户可以在其中将对象从一个窗口复制或移动到另一个窗口。

基于 MIME 的拖放数据传输基于 QDrag 类。 QMimeData 对象将数据与其相应的 MIME 类型相关联。这些对象存储在剪贴板上,然后用于拖放过程中。

以下 QMimeData 类函数允许方便地检测和使用 MIME 类型。

Tester

Getter

Setter

MIME Types

hasText()

text()

setText()

text/plain

hasHtml()

html()

setHtml()

text/html

hasUrls()

urls()

setUrls()

text/uri-list

hasImage()

imageData()

setImageData()

image/ *

hasColor()

colorData()

setColorData()

application/x-color

许多 QWidget 对象支持拖放活动。允许拖拽其数据的对象已设置 setDragEnabled(),它必须设置为 true。另一方面,部件应响应拖放事件,以存储拖到其中的数据。

  1. DragEnterEvent 提供一个事件,该事件会在拖拽操作进入目标部件时发送给目标部件。

  2. 在拖放操作进行中时,将使用 DragMoveEvent

  3. 当拖放操作离开部件时,将生成 DragLeaveEvent

  4. 另一方面, DropEvent 发生在放置完成后。可以有条件地接受或拒绝事件的提议操作。

Example

在以下代码中, DragEnterEvent 验证事件的 MIME 数据是否包含文本。如果是,则接受事件的建议操作并将文本作为 ComboBox 中的新项进行添加。

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class combo(QComboBox):
   def __init__(self, title, parent):
      super(combo, self).__init__( parent)
      self.setAcceptDrops(True)

   def dragEnterEvent(self, e):
      print (e)

      if e.mimeData().hasText():
         e.accept()
      else:
         e.ignore()

   def dropEvent(self, e):
      self.addItem(e.mimeData().text())

class Example(QWidget):
   def __init__(self):
      super(Example, self).__init__()

      self.initUI()

   def initUI(self):
      lo = QFormLayout()
      lo.addRow(QLabel("Type some text in textbox and drag it into combo box"))

      edit = QLineEdit()
      edit.setDragEnabled(True)
      com = combo("Button", self)
      lo.addRow(edit,com)
      self.setLayout(lo)
      self.setWindowTitle('Simple drag and drop')
def main():
   app = QApplication(sys.argv)
   ex = Example()
   ex.show()
   app.exec_()

if __name__ == '__main__':
   main()

上述代码生成以下输出 -

drag and drop output

PyQt5 - Database Handling

PyQt5 库包含 QtSql 模块。它是一个复杂的类系统,用于与许多基于 SQL 的数据库通信。它的 QSqlDatabase 提供通过连接对象进行访问。以下是当前可用的 SQL 驱动程序的列表:

Sr.No.

Driver Type & Description

1

QDB2 IBM DB2

2

QIBASE Borland InterBase Driver

3

QMYSQL MySQL Driver

4

QOCI Oracle Call Interface Driver

5

QODBC ODBC 驱动程序(包括 Microsoft SQL Server)

6

QPSQL PostgreSQL Driver

7

QSQLITE SQLite 3 或更高版本

8

QSQLITE2 SQLite version 2

Example

对于本章,使用静态方法与 SQLite 数据库建立连接 −

db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('sports.db')

QSqlDatabase 类的其他方法如下:

Sr.No.

Methods & Description

1

setDatabaseName() 设置需要建立连接的数据库的名称

2

setHostName() 设置安装数据库的主机的名称

3

setUserName() 指定用于连接的用户名

4

setPassword() 设置连接对象的密码(如果存在)

5

commit() 提交事务并在成功时返回 true

6

rollback() 回滚数据库事务

7

close() Closes the connection

QSqlQuery 类具有执行和操作 SQL 命令的功能。可以执行 DDL 和 DML 类型的 SQL 查询。第一步是使用以下语句创建 SQlite 数据库 −

db = QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('sportsdatabase.db')

接下来,使用 QSqlQuery() 方法获取查询对象并调用其最重要的方法 exec_(), 它将包含要执行的 SQL 语句的字符串作为参数。

query = QtSql.QSqlQuery()
query.exec_("create table sportsmen(id int primary key, " "firstname varchar(20), lastname varchar(20))")

下面的脚本创建了一个 sports.db SQLite 数据库,其中包含一个有五条记录填充的 sportsperson 表。

import sys
from PyQt5.QtSql import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def createDB():
   db = QSqlDatabase.addDatabase('QSQLITE')
   db.setDatabaseName('sportsdatabase.db')

   if not db.open():
      msg = QMessageBox()
      msg.setIcon(QMessageBox.Critical)
      msg.setText("Error in Database Creation")
      retval = msg.exec_()
      return False
   query = QSqlQuery()

   query.exec_("create table sportsmen(
      id int primary key, ""firstname varchar(20), lastname varchar(20))")

   query.exec_("insert into sportsmen values(101, 'Roger', 'Federer')")
   query.exec_("insert into sportsmen values(102, 'Christiano', 'Ronaldo')")
   query.exec_("insert into sportsmen values(103, 'Ussain', 'Bolt')")
   query.exec_("insert into sportsmen values(104, 'Sachin', 'Tendulkar')")
   query.exec_("insert into sportsmen values(105, 'Saina', 'Nehwal')")
   return True

if __name__ == '__main__':
   app = QApplication(sys.argv)
   createDB()

要确认 SQLite 数据库是否已创建并向其添加 sportsmen 表中的上述记录,请使用名为 SQLiteStudio 的 SQLite GUI 实用程序。

database handling

PyQt 中的 QSqlTableModel 类是一个高级接口,它为以单个表的形式读写记录提供了可编辑的数据模型。此模型用于填充 QTableView 对象。它向用户呈现一个可滚动的可编辑视图,可以将其放在任何顶级窗口上。

QSqlTableModel 对象以以下方式声明:

model = QtSql.QSqlTableModel()

可以将其编辑策略设置为下列任意一项 −

QSqlTableModel.OnFieldChange

所有更改都将立即应用

QSqlTableModel.OnRowChange

当用户选择不同的行时将应用更改

QSqlTableModel.OnManualSubmit

所有更改在调用 submitAll() 或 revertAll() 之前都会缓存起来

Example

在以下示例中,sportsperson 表用作模型,并且策略设置为 −

model.setTable('sportsmen')
model.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)
   model.select()

QTableView 类是 PyQt 中模型/视图框架的一部分。QTableView 对象创建如下 −

view = QtGui.QTableView()
view.setModel(model)
view.setWindowTitle(title)
return view

该 QTableView 对象和两个 QPushButton 窗口小部件将被添加到顶层 QDialog 窗口。add 按钮的 clicked() 信号连接到 addrow(),后者对模型表格执行 insertRow()。

button.clicked.connect(addrow)
def addrow():
   print model.rowCount()
   ret = model.insertRows(model.rowCount(), 1)
   print ret

与删除按钮相关联的槽执行一个删除行的 lambda 函数,该行由用户选择。

btn1.clicked.connect(lambda: model.removeRow(view1.currentIndex().row()))

完整代码如下所示:

import sys
from PyQt5.QtSql import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def initializeModel(model):
   model.setTable('sportsmen')
   model.setEditStrategy(QSqlTableModel.OnFieldChange)
   model.select()
   model.setHeaderData(0, Qt.Horizontal, "ID")
   model.setHeaderData(1, Qt.Horizontal, "First name")
   model.setHeaderData(2, Qt.Horizontal, "Last name")

def createView(title, model):
   view = QTableView()
   view.setModel(model)
   view.setWindowTitle(title)
   return view

def addrow():
   print (model.rowCount())
   ret = model.insertRows(model.rowCount(), 1)
   print (ret)

def findrow(i):
   delrow = i.row()

if __name__ == '__main__':
   app = QApplication(sys.argv)
   db = QSqlDatabase.addDatabase('QSQLITE')
   db.setDatabaseName('sportsdatabase.db')
   model = QSqlTableModel()
   delrow = -1
   initializeModel(model)

   view1 = createView("Table Model (View 1)", model)
   view1.clicked.connect(findrow)

   dlg = QDialog()
   layout = QVBoxLayout()
   layout.addWidget(view1)

   button = QPushButton("Add a row")
   button.clicked.connect(addrow)
   layout.addWidget(button)

   btn1 = QPushButton("del a row")
   btn1.clicked.connect(lambda: model.removeRow(view1.currentIndex().row()))
   layout.addWidget(btn1)

   dlg.setLayout(layout)
   dlg.setWindowTitle("Database Demo")
   dlg.show()
   sys.exit(app.exec_())

上述代码生成以下输出 -

database handling output

尝试添加和删除一些记录,然后返回 SQLiteStudio 以确认事务。

PyQt5 - Drawing API

PyQt 中的所有 QWidget 类都是从 QPaintDevice 类派生的子类。 QPaintDevice 对可以通过 QPainter 绘图的二维空间进行抽象。画图设备的尺寸以从左上角开始的像素为单位进行测量。

QPainter 类在窗口小部件和其他可绘制设备(如打印机)上执行低级绘制。通常情况下,它用于窗口小部件的绘制事件。 QPaintEvent 发生在窗口小部件的外观更新时。

通过调用 begin() 方法启用该绘制程序,而 end() 方法停用此绘制程序。其间,通过列在下一张表中的适当方法绘制所需模式。

Sr.No.

Methods & Description

1

begin() 开始在目标设备上绘制

2

drawArc() 在起始角和结束角之间绘制弧形

3

drawEllipse() 在矩形内绘制椭圆

4

drawLine() 绘制带有指定端点的线

5

drawPixmap() 从图像文件中提取位图并将其显示在指定位置

6

drwaPolygon() 利用坐标阵列绘制多边形

7

drawRect() 从左上角坐标处绘制给定宽和高的矩形

8

drawText() 在给定坐标处显示文本

9

fillRect() 用 QColor 变量填充矩形

10

setBrush() 设置笔刷样式以进行绘制

11

setPen() 设置用于绘制的笔的颜色、大小和样式

Example

以下代码中使用了 PyQt 绘图方法的各种方法。

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class Example(QWidget):
   def __init__(self):
      super(Example, self).__init__()
      self.initUI()

   def initUI(self):
      self.text = "hello world"
      self.setGeometry(100,100, 400,300)
      self.setWindowTitle('Draw Demo')
      self.show()

   def paintEvent(self, event):
      qp = QPainter()
      qp.begin(self)
      qp.setPen(QColor(Qt.red))
      qp.setFont(QFont('Arial', 20))
      qp.drawText(10,50, "hello Python")
      qp.setPen(QColor(Qt.blue))
      qp.drawLine(10,100,100,100)
      qp.drawRect(10,150,150,100)
      qp.setPen(QColor(Qt.yellow))
      qp.drawEllipse(100,50,100,50)
      qp.drawPixmap(220,10,QPixmap("pythonlogo.png"))
      qp.fillRect(20,175,130,70,QBrush(Qt.SolidPattern))
      qp.end()

def main():
   app = QApplication(sys.argv)
   ex = Example()
   sys.exit(app.exec_())

if __name__ == '__main__':
   main()

上述代码生成以下输出 -

database handling outputs

PyQt5 - BrushStyle Constants

在本章中,我们将学习画笔样式常量。

Brush Style Constants

下面给出画笔样式常量:

Qt.NoBrush

No brush pattern

Qt.SolidPattern

Uniform color

Qt.Dense1Pattern

Extremely dense brush pattern

Qt.HorPattern

Horizontal lines

Qt.VerPattern

Vertical lines

Qt.CrossPattern

交叉水平线和垂直线

Qt.BDiagPattern

Backward diagonal lines

Qt.FDiagPattern

Forward diagonal lines

Qt.DiagCrossPattern

Crossing diagonal lines

Predefined QColor Styles

下面给出预定义的 QColor 样式:

Qt.NoBrush

No brush pattern

Qt.SolidPattern

Uniform color

Qt.Dense1Pattern

Extremely dense brush pattern

Qt.HorPattern

Horizontal lines

Qt.VerPattern

Vertical lines

Qt.CrossPattern

交叉水平线和垂直线

Qt.BDiagPattern

Backward diagonal lines

Qt.FDiagPattern

Forward diagonal lines

Qt.DiagCrossPattern

Crossing diagonal lines

Predefined QColor Objects

下面给出预定义的 QColor 对象:

Qt.white

Qt.black

Qt.red

Qt.darkRed

Qt.green

Qt.darkGreen

Qt.blue

Qt.cyan

Qt.magenta

Qt.yellow

Qt.darkYellow

Qt.gray

PyQt5 - QClipboard

QClipboard 类提供对系统剪贴板的访问,它提供了一个在应用程序之间复制和粘贴数据的简单机制。它的操作与 QDrag 类相似并使用类似的数据类型。

QApplication 类具有静态方法 clipboard() ,它返回对剪贴板对象的引用。任何类型的 MimeData 都可以复制到或从剪贴板粘贴。

以下是一些常用的剪贴板类的方法: -

Sr.No.

Methods & Description

1

clear() Clears clipboard contents

2

setImage() Copies QImage into clipboard

3

setMimeData() 将 MIME 数据设置到剪贴板

4

setPixmap() 在剪贴板中复制 Pixmap 对象

5

setText() Copies QString in clipboard

6

text() Retrieves text from clipboard

与剪贴板对象关联的信号是 -

Sr.No.

Method & Description

1

dataChanged() Whenever clipboard data changes

Example

在以下示例中,两个 TextEdit 对象和两个 Pushbutton 被添加到一个顶级窗口。

首先,实例化剪贴板对象。textedit 对象的 Copy() 方法将数据复制到系统剪贴板。当按下粘贴按钮时,它会获取剪贴板数据并将其粘贴到另一个 textedit 对象。

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class Example(QWidget):
   def __init__(self):
      super(Example, self).__init__()

      self.initUI()

   def initUI(self):
      hbox = QVBoxLayout()
      self.edit1=QTextEdit()
      hbox.addWidget(self.edit1)
      self.btn1=QPushButton("Copy")
      hbox.addWidget(self.btn1)
      self.edit2=QTextEdit()
      self.btn2=QPushButton("Paste")
      hbox.addWidget(self.edit2)
      hbox.addWidget(self.btn2)
      self.btn1.clicked.connect(self.copytext)
      self.btn2.clicked.connect(self.pastetext)
      self.setLayout(hbox)

      self.setGeometry(300, 300, 300, 200)
      self.setWindowTitle('Clipboard')
      self.show()

   def copytext(self):

      #clipboard.setText(self.edit1.copy())
      self.edit1.copy()
      print (clipboard.text())

      msg=QMessageBox()
      msg.setText(clipboard.text()+" copied on clipboard")
      msg.exec_()

   def pastetext(self):
      self.edit2.setText(clipboard.text())

app = QApplication(sys.argv)
clipboard=app.clipboard()
ex = Example()
ex.setWindowTitle("clipboard Example")
sys.exit(app.exec_())

上述代码生成以下输出 -

qclipboard

PyQt5 - QPixmap Class

QPixmap 类提供图像的非屏幕表示。它可以用作 QPaintDevice 对象,也可以加载到另一个小部件,通常是标签或按钮。

Qt API 还有另一个类似类 QImage ,经过优化,可进行 I/O 及其他像素操作。另一方面,Pixmap 已针对显示在屏幕上进行了优化。两种格式可以相互转换。

可以读入 QPixmap 中的图像文件类型如下 -

BMP

Windows Bitmap

GIF

Graphic Interchange Format (optional)

JPG

Joint Photographic Experts Group

JPEG

Joint Photographic Experts Group

PNG

Portable Network Graphics

PBM

Portable Bitmap

PGM

Portable Graymap

PPM

Portable Pixmap

XBM

X11 Bitmap

XPM

X11 Pixmap

以下方法对于处理 QPixmap 对象很有用 -

Sr.No.

Methods & Description

1

copy() 从 QRect 对象复制像素图数据

2

fromImage() 将 QImage 对象转换为 QPixmap

3

grabWidget() 从给定小部件创建像素图

4

grabWindow() 创建窗口中数据的像素图

5

Load() 将图像文件加载为像素图

6

save() 保存 QPixmap 对象为文件

7

toImage 将 QPixmap 转换为 QImage

QPixmap 最常见的用途是在标签/按钮上显示图像。

Example

以下示例显示了通过使用 setPixmap() 方法在 QLabel 上显示的图像。

完整代码如下所示:

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def window():
   app = QApplication(sys.argv)
   win = QWidget()
   l1 = QLabel()
   l1.setPixmap(QPixmap("python.png"))

   vbox = QVBoxLayout()
   vbox.addWidget(l1)
   win.setLayout(vbox)
   win.setWindowTitle("QPixmap Demo")
   win.show()
   sys.exit(app.exec_())

if __name__ == '__main__':
   window()

上述代码生成以下输出 -

qpixmap class