数据STUDIO

PyQt6,用 Python 开发高级 GUI

Python 凭借其简洁易用和庞大的生态系统,已成为各领域开发人员的首选语言。在创建桌面应用程序方面,Qt6 无疑是一款强大的工具包。Qt6 是 Qt 框架的最新版本,相比前代产品,它提供了增强的特性和功能,使其成为构建跨平台 GUI 应用程序的首选。

Image

Qt6 的设计理念是更加模块化、高效和适应性。它在图形处理、性能和易用性方面进行了改进,确保开发人员拥有一个强大的应用程序框架。借助 PyQt6 或 PySide6 绑定,Python 与 Qt6 的集成将 Python 的易脚本编写能力与 Qt 丰富的 GUI 功能完美结合。

今天就跟云朵君一起学习 PyQt6 吧~

设置开发环境

要开始使用 Python 开发 Qt6 应用程序,你需要设置开发环境。这包括安装 Python 和 Qt6 绑定。PyQt6 和 PySide6 是 Python 的两个主要绑定。

  1. 安装 Python:从官方网站下载并安装最新版本的 Python。确保将 Python 添加到系统的 PATH 中。
  2. 安装PyQt6或PySide6:
  • PyQt6:你可以使用 pip 安装 PyQt6:
pip install PyQt6
  • PySide6:同样,对于 PySide6:
pip install PySide6
  1. Qt Designer:为了直观地设计你的应用程序,你可能需要安装 Qt Designer,它包含在 Qt 工具包中。你也可以通过 pip 安装它:
pip install PyQt6-tools   # 对于 PyQt6
pip install pyside6-tools # 对于 PySide6

基本小部件

QPushButton

QPushButton是一个可点击的按钮,用于执行操作或回答问题。

from PyQt6.QtWidgets import QApplication, QPushButton, QWidget, QVBoxLayout

defon_click():
print ( '按钮被点击!' ) 

app = QApplication([]) 
window = QWidget() 
layout = QVBoxLayout() 

button = QPushButton( '点击我' ) 
button.clicked.connect(on_click)   # 将信号连接到插槽
layout.addWidget(button) 

window.setLayout(layout) 
window.show() 
app. exec ()

QLabel

QLabel显示文本或图像。它通常用于指示表单字段、提供提示或显示图像。

from PyQt6.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout

app = QApplication([]) 
window = QWidget() 
layout = QVBoxLayout() 

label = QLabel( 'Hello, PyQt6!' ) 
layout.addWidget(label) 

window.setLayout(layout) 
window.show() 
app.exec ( )

布局管理

QVBoxLayout 和 QHBoxLayout

QVBoxLayout 和 QHBoxLayout用于垂直和水平排列小部件。

from PyQt6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QHBoxLayout, QWidget 

app = QApplication([]) 
window = QWidget() 

v_layout = QVBoxLayout() 
h_layout = QHBoxLayout() 

btn1 = QPushButton('按钮 1') 
btn2 = QPushButton('按钮 2') 

v_layout.addWidget(btn1) 
h_layout.addWidget(btn2) 

window.setLayout(v_layout) 
window.setLayout(h_layout) 
window.show() 
app.exec()

对话框

QMessageBox

QMessageBox用于显示消息。

from PyQt6.QtWidgets import QApplication, QMessageBox
app = QApplication([]) 
msg_box = QMessageBox() 
msg_box.setText( "这是一个消息框。" ) 
msg_box.exec ( )

高级小部件

QTableView

QTableView提供使用模型来管理数据的表格视图。

from PyQt6.QtWidgets import QApplication, QTableView, QWidget, QVBoxLayout
from PyQt6.QtCore import QAbstractTableModel, Qt

classMyTableModel(QAbstractTableModel):
defrowCount(self,parent):
return 5    # 示例行数

defcolumnCount(self,parent):
return 3   # 示例列数

defdata(self,index,role):
ifrole == Qt.ItemDataRole.DisplayRole:

returnf"Cell ({index.row()},{index.column()})"

app = QApplication([])
window = QWidget()
layout = QVBoxLayout()
table_view = QTableView()
model = MyTableModel()
table_view.setModel(model)

layout.addWidget(table_view)
window.setLayout(layout)
window.show()
app.exec()

图形视图框架

QGraphicsView 和 QGraphicsScene

QGraphicsView是一个提供QGraphicsScene可视化表示的小部件。它用于复杂的图形和自定义项目。

from PyQt6.QtWidgets import QApplication, QGraphicsScene, QGraphicsView

app = QApplication([])
scene = QGraphicsScene()
scene.addText("Hello, PyQt6 Graphics View!")

view = QGraphicsView(scene)
view.show()
app.exec()

自定义小部件

创建自定义小部件涉及从现有小部件或直接从现有小部件进行QWidget子类化,然后覆盖方法来定制行为和外观。

from PyQt6.QtWidgets import QApplication, QWidget, QPainter, QBrush, QPen
from PyQt6.QtCore import Qt

classCustomWidget(QWidget):
defpaintEvent(self, event):
        painter = QPainter(self)
        painter.setPen(QPen(Qt.blue, 8, Qt.SolidLine))
        painter.setBrush(QBrush(Qt.green, Qt.SolidPattern))
        painter.drawRect(10, 10, 200, 200)

app = QApplication([])
custom_widget = CustomWidget()
custom_widget.show()
app.exec()

输入小部件

QLineEdit

QLineEdit小部件允许用户输入和编辑单行纯文本。

from PyQt6.QtWidgets import QApplication, QLineEdit, QWidget, QVBoxLayout

app = QApplication([]) 
window = QWidget() 
layout = QVBoxLayout() 

line_edit = QLineEdit() 
line_edit.setPlaceholderText( "输入一些文本..." ) 
layout.addWidget(line_edit) 

window.setLayout(layout) 
window.show() 
app.exec ()

QTextEdit

QTextEdit提供了一个用于编辑和显示纯文本和富文本的小部件。

from PyQt6.QtWidgets import QApplication, QTextEdit, QWidget, QVBoxLayout

app = QApplication([]) 
window = QWidget() 
layout = QVBoxLayout() 

text_edit = QTextEdit() 
text_edit.setPlainText( "这是一个 QTextEdit 小部件。您可以编辑我!" ) 
layout.addWidget(text_edit) 

window.setLayout(layout) 
window.show() 
app. exec ()

选择小部件

QComboBox

QComboBox是一个小部件,允许用户从选项列表中选择或输入自己的选项。

from PyQt6.QtWidgets import QApplication, QComboBox, QWidget, QVBoxLayout

app = QApplication([]) 
window = QWidget() 
layout = QVBoxLayout() 

combo_box = QComboBox() 
combo_box.addItems(["选项 1", "选项 2" , "选项 3"]) 
layout.addWidget(combo_box) 
window.setLayout(layout) 
window.show() 
app.exec()

QSpinBox 和 QDoubleSpinBox

QSpinBox和QDoubleSpinBox是分别允许用户从整数或浮点值范围中进行选择的小部件。

from PyQt6.QtWidgets import QApplication, QSpinBox, QDoubleSpinBox, QWidget, QVBoxLayout

app = QApplication([]) 
window = QWidget() 
layout = QVBoxLayout() 

spin_box = QSpinBox() 
spin_box.setRange(0, 100) 
layout.addWidget(spin_box) 

double_spin_box = QDoubleSpinBox() 
double_spin_box.setRange(0.0, 100.0) 
layout.addWidget(double_spin_box) 

window.setLayout(layout) 
window.show() 
app.exec()

控制部件

QSlider

QSlider是一个控制小部件,允许用户通过滑动手柄从线性范围中选择一个值。

from PyQt6.QtWidgets import QApplication, QSlider, QWidget, QVBoxLayout
from PyQt6.QtCore import Qt 

app = QApplication([]) 
window = QWidget() 
layout = QVBoxLayout() 

slider = QSlider(Qt.Orientation.Horizontal) 
slider.setRange(0 , 100 ) 
layout.addWidget(slider) 

window.setLayout(layout) 
window.show() 
app.exec()

QDial

QDial 与 QSlider 类似,但提供圆形拨号界面。

from PyQt6.QtWidgets import QApplication, QDial, QWidget, QVBoxLayout

app = QApplication([]) 
window = QWidget() 
layout = QVBoxLayout() 

dial = QDial() 
dial.setRange(0 , 100) 
layout.addWidget(dial) 

window.setLayout(layout) 
window.show() 
app.exec()

显示小部件

QProgressBar

QProgressBar提供水平或垂直进度条。

from PyQt6.QtWidgets import QApplication, QProgressBar, QWidget, QVBoxLayout

app = QApplication([]) 
window = QWidget() 
layout = QVBoxLayout() 

progress_bar = QProgressBar() 
progress_bar.setRange( 0 , 100 ) 
progress_bar.setValue( 75 ) 
layout.addWidget(progress_bar) 

window.setLayout(layout) 
window.show() 
app.exec ( )

QLCD编号

QLCDNumber以类似 LCD 的风格显示数字。

from PyQt6.QtWidgets import QApplication, QLCDNumber, QWidget, QVBoxLayout

app = QApplication([]) 
window = QWidget() 
layout = QVBoxLayout() 

lcd_number = QLCDNumber() 
lcd_number.display(123) 
layout.addWidget(lcd_number) 

window.setLayout(layout) 
window.show() 
app.exec()

创建第一个 Qt6 应用程序

下面就和云朵君一起开始创建一个简单的 Qt6 应用程序,它会打开一个带有问候消息的窗口。此示例使用 PyQt6,但你可以通过更改 import 语句轻松地将其适配到 PySide6。

import sys
from PyQt6.QtWidgets import QApplication, QLabel, QWidget

app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle('Hello Qt6')
label = QLabel('Welcome to Qt6 with Python', window)
window.setGeometry(100, 100, 280, 80)
label.move(50, 20)
window.show()
sys.exit(app.exec())

探索 Qt6 GUI 元素

小部件

小部件是 Qt6 应用程序的基石。从简单的标签到复杂的滑块,Qt6 提供了丰富的小部件。以下是创建 QPushButton 的方法:

from PyQt6.QtWidgets import QApplication, QPushButton

app = QApplication([])
button = QPushButton('Click Me')
button.clicked.connect(lambda: print('Button clicked!'))
button.show()
app.exec()

布局

布局有助于组织窗口内的小部件。Qt6 提供了多种布局,例如 QHBoxLayout、QVBoxLayout 和 GridLayout。以下是使用 QVBoxLayout 的示例:

from PyQt6.QtWidgets import QApplication, QVBoxLayout, QWidget, QPushButton

app = QApplication([]) 
window = QWidget() 
layout = QVBoxLayout() 
layout.addWidget(QPushButton('按钮 1')) 
layout.addWidget(QPushButton('按钮 2')) 
window.setLayout(layout) 
window.show() 
app.exec ( )

对话框和窗口

对话框是用于用户交互的特殊窗口。在 Qt6 中创建对话框非常简单:

from PyQt6.QtWidgets import QApplication, QDialog, QDialogButtonBox, QVBoxLayout

app = QApplication([]) 
dialog = QDialog() 
buttonBox = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) 
buttonBox.accepted.connect(dialog.accept) 
buttonBox.rejected.connect(dialog.reject) 
layout = QVBoxLayout() 
layout.addWidget(buttonBox) 
dialog.setLayout(layout) 
dialog.exec()

高级 Qt6 功能

图形和自定义小部件

Qt6 增强了对图形的支持,允许创建自定义小部件和复杂的图形元素。以下是绘制简单矩形的代码片段:

from PyQt6.QtWidgets import QApplication, QWidget
from PyQt6.QtGui import QPainter, QColor
from PyQt6.QtCore import Qt

classMyWidget(QWidget):
defpaintEvent(self, event):
        painter = QPainter(self)
        painter.setBrush(QColor(255, 0, 0, 180))
        painter.drawRect(10, 10, 100, 100)

app = QApplication([])
myWidget = MyWidget()
myWidget.show()
app.exec()

数据库集成

Qt6 提供了强大的数据库集成支持,可以轻松连接到主流数据库。以下是连接到 SQLite 数据库的方法:

from PyQt6.QtSql import QSqlDatabase, QSqlQuery

db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName(":memory:")
if db.open():
    query = QSqlQuery()
    query.exec("CREATE TABLE people (id INTEGER PRIMARY KEY, name TEXT)")

Qt6 中的多线程

Qt6 支持多线程,这对于在执行长时间操作时保持 UI 的响应至关重要。以下是使用 QThread 的示例:

from PyQt6.QtCore import QThread, pyqtSignal
from PyQt6.QtWidgets import QApplication, QLabel

classWorker(QThread):
    updated = pyqtSignal(str)

defrun(self):
# Long running task
        self.updated.emit("Task Finished")

app = QApplication([])
label = QLabel("Starting...")
label.show()

worker = Worker()
worker.updated.connect(lambda text: label.setText(text))
worker.start()

app.exec()

高级 PyQt6 概念

PyQt6 的高级概念可用于创建更复杂、交互性更强的 GUI 应用程序。以下是一些高级主题的讲解和代码示例,包括模型-视图-控制器 (MVC) 架构、自定义控件、图形视图框架以及 PyQt6 中的线程处理。

1. 模型-视图-控制器(MVC)架构

MVC 架构将数据模型、用户界面和控制逻辑分离到不同的组件中。这种分离使得应用程序更易于维护和扩展。

示例:为列表编辑器应用程序实现简单的 MVC。

from PyQt6.QtWidgets import QApplication, QMainWindow, QListWidget, QVBoxLayout, QWidget, QPushButton

classModel:
def__init__(self, data):
        self.data = data

classView(QMainWindow):
def__init__(self, model):
        super().__init__()
        self.model = model
        self.initUI()

definitUI(self):
        self.setWindowTitle('MVC Example')
        self.listWidget = QListWidget()
for entry in self.model.data:
            self.listWidget.addItem(entry)

        self.addButton = QPushButton("Add Item")
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.listWidget)
        self.layout.addWidget(self.addButton)

        self.container = QWidget()
        self.container.setLayout(self.layout)
        self.setCentralWidget(self.container)

classController:
def__init__(self, model, view):
        self.model = model
        self.view = view
        self.connectSignals()

defconnectSignals(self):
        self.view.addButton.clicked.connect(self.addItem)

defaddItem(self):
        itemText = f"Item {len(self.model.data) + 1}"
        self.model.data.append(itemText)
        self.view.listWidget.addItem(itemText)

if __name__ == '__main__':
    app = QApplication([])
    model = Model(['Item 1', 'Item 2', 'Item 3'])
    view = View(model)
    controller = Controller(model, view)
    view.show()
    app.exec()

2. 自定义小部件

创建自定义小部件涉及对现有的 PyQt6 小部件或基QWidget类进行子类化,然后重写方法来自定义小部件的外观和行为。

示例:创建自定义按钮小部件。

from PyQt6.QtWidgets import QPushButton, QApplication, QWidget, QVBoxLayout
from PyQt6.QtGui import QPainter, QColor
from PyQt6.QtCore import Qt

classColorButton(QPushButton):
def__init__(self, color, parent=None):
        super().__init__(parent)
        self.color = color

defpaintEvent(self, event):
        painter = QPainter(self)
        painter.setBrush(QColor(self.color))
        painter.drawRect(self.rect())

if __name__ == '__main__':
    app = QApplication([])
    window = QWidget()
    layout = QVBoxLayout()
    redButton = ColorButton('red')
    greenButton = ColorButton('green')
    layout.addWidget(redButton)
    layout.addWidget(greenButton)
    window.setLayout(layout)
    window.show()
    app.exec()

3. 图形视图框架

图形视图框架提供了基于场景的画布,用于管理和与大量自定义 2D 图形项目进行交互。

示例:在场景中显示自定义项目。

from PyQt6.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QGraphicsEllipseItem
from PyQt6.QtCore import Qt

classGraphicsExample(QGraphicsView):
def__init__(self):
        super().__init__()
        self.scene = QGraphicsScene()
        self.setScene(self.scene)
        self.initUI()

definitUI(self):
        ellipse = QGraphicsEllipseItem(0, 0, 100, 50)
        self.scene.addItem(ellipse)

if __name__ == '__main__':
    app = QApplication([])
    view = GraphicsExample()
    view.show()
    app.exec()

4. PyQt6 中的线程

对于长时间运行的操作,将工作负载移至单独的线程可防止 GUI 卡死。PyQt6 不仅集成了 Python 的线程模块,还提供了自己的QThread线程管理类。

示例:QThread用于后台任务。

from PyQt6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
from PyQt6.QtCore import QThread, pyqtSignal
import time

classWorker(QThread):
    finished = pyqtSignal()

defrun(self):
        time.sleep(5)  # Simulate a long-running task
        self.finished.emit()

classMainWindow(QWidget):
def__init__(self):
        super().__init__()
        self.button = QPushButton("Start Task")
        self.button.clicked.connect(self.startTask)
        layout = QVBoxLayout()
        layout.addWidget(self.button)
        self.setLayout(layout)

defstartTask(self):
        self.thread = Worker()
        self.thread.finished.connect(self.taskFinished)
        self.thread.start()

deftaskFinished(self):
        self.button.setText("Task Finished")

if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec()

这些示例展示了 PyQt6 在开发复杂应用程序方面的多功能性和强大功能。通过利用这些先进的概念,开发人员可以创建兼具功能性和视觉吸引力的应用程序。

简单计算器示例

创建一个简单的计算器是熟悉 PyQt6 的好方法,它可以演示如何与小部件交互、处理事件以及执行基本操作。以下是创建可执行加、减、乘、除运算的基本计算器的分步指南。

步骤1:导入PyQt6模块

首先,你需要从 PyQt6 导入必要的模块。

from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QLineEdit
import sys

步骤 2:创建计算器的 GUI

为计算器的 GUI 定义一个类。该类将创建计算器窗口、布局、显示区域(用于显示计算结果或输入)以及用于数字和运算的按钮。

classSimpleCalculator(QWidget):
def__init__(self):
        super ().__init__() 
        self.setWindowTitle("Simple Calculator") 
        self.create_ui() 

defcreate_ui(self):
# 创建垂直布局
        self.layout = QVBoxLayout() 

# 创建显示行编辑
        self.display = QLineEdit() 
# 使显示只读
        self.display.setReadOnly( True ) 
        self.layout.addWidget(self.display) 

        self.create_buttons() 
        self.setLayout(self.layout) 

defcreate_buttons(self):
# 计算器的按钮
        buttons = [ 
'7' , '8' , '9' , '/' , 
'4' , '5' , '6' , '*'
            , ' 1' , '2' , ' 3' , '-' , 
'0' , '.' , '=' , '+'
         ] 

# 创建按钮并将其添加到布局
for button in buttons: 
            btn = QPushButton(button) 
            btn.clicked.connect(self.on_click) 
            self.layout.addWidget(btn) 

defon_click(self):
# 获取被点击的按钮
        button = self.sender() 
# 获取按钮的文本
        text = button.text() 
if text == "=" : 
# 如果按下了等于按钮,则评估表达式
try : 
                result = str(eval (self.display.text())) 
                self.display.setText(result) 
except Exception as e: 
                self.display.setText("Error") 
else : 
# 如果按下了任何其他按钮,则将其文本添加到显示
            self.display.setText(self.display.text() + text)

步骤3:初始化并显示计算器

定义SimpleCalculator类之后,你需要在启动应用程序的主循环之前创建一个QApplication实例和计算器。

if __name__ == "__main__":
    app = QApplication(sys.argv)
    calculator = SimpleCalculator()
    calculator.show()
    sys.exit(app.exec())

这个简单的计算器允许用户使用按钮输入基本的算术运算,并在点击“=”按钮时显示结果。eval函数用于计算显示中的字符串表达式,这是一种简单但可能不安全的执行动态表达式的方法。对于实际应用,请考虑实现更安全的计算机制,以避免eval相关的风险。

此示例涵盖了基本操作,并为构建更复杂的功能(例如处理更复杂的数学运算、改进错误处理和增强用户界面)提供了基础。

设计原则和最佳实践

使用 Qt6 和 Python 进行开发时,请考虑以下最佳实践:

  • 模块化设计:将代码组织成模块和类。
  • 信号和槽机制:利用Qt的信号和槽机制进行对象之间的通信。
  • 资源管理:注意资源管理,尤其是图形和数据库连接。
  • 用户体验:关注用户体验,确保你的应用程序直观且响应迅速。

真实世界的应用示例

VLC 媒体播放器、Calibre 和 Anki 是 Qt6 多功能性的典型代表。分析这些应用程序会发现一些共同的挑战,例如处理多媒体内容、管理庞大的库以及实现间隔重复算法。

写在最后

Python 和 Qt6 为开发跨平台桌面应用程序提供了强大的组合。利用 Python 的简洁性和 Qt6 全面的 GUI 元素,开发人员可以相对轻松地创建复杂的应用程序。

Qt6 丰富的 GUI 元素,加上 Python 的简洁易读性,确保开发者能够高效地设计出不仅视觉上赏心悦目,而且功能强大、响应迅速的界面。丰富的小部件、强大的事件处理以及信号和槽机制,助力创建出在当今软件领域脱颖而出的交互式、用户友好的应用程序。