引言
在 Python GUI 开发领域,PyQt6 是首选工具。它基于 Qt 框架,融合了 Python 的简洁易用和 Qt 的丰富功能,既能快速搭建简单工具,也能开发复杂的商业软件。
Python PyQt6 桌面应用开发的全流程。内容包括环境搭建、核心组件(窗口、标签、按钮、输入框等)的使用、布局管理(垂直、水平、网格布局)、信号与槽机制的事件处理,以及菜单、对话框、多线程、QSS 美化和自定义组件等进阶功能。文章通过计算器实战案例展示了如何整合上述知识点,并总结了常见错误避坑指南和学习建议,帮助开发者从零开始掌握 PyQt6 开发。

在 Python GUI 开发领域,PyQt6 是首选工具。它基于 Qt 框架,融合了 Python 的简洁易用和 Qt 的丰富功能,既能快速搭建简单工具,也能开发复杂的商业软件。
相比 Tkinter 的基础简陋,PyQt6 提供了更现代化的界面组件和更灵活的定制能力;相比 wxPython 的生态封闭,PyQt6 拥有更庞大的社区支持和更完善的文档。无论是新手入门 GUI 开发,还是开发者升级桌面应用质感,PyQt6 都能满足需求。
本文从实际开发场景出发,通过基础入门、组件详解、布局管理、事件处理、进阶实战的递进结构,搭配可直接运行的代码示例和详细注释,帮你从 0 到 1 掌握 PyQt6。
在众多 Python GUI 库中,PyQt6 的优势尤为突出,尤其适合追求界面质感和功能完整性的开发场景:
无论是开发个人工具(如批量处理脚本界面)、企业应用(如客户管理系统),还是开源项目(如数据分析工具),PyQt6 都能胜任。
PyQt6 是第三方库,需要手动安装,推荐使用 Python 3.8 及以上版本(兼容性更好):
# 基础安装(包含核心组件)
pip install pyqt6
# 完整安装(包含 Qt Designer 等工具,推荐)
pip install pyqt6-tools
安装完成后,运行以下代码,若弹出窗口则说明安装成功:
from PyQt6.QtWidgets import QApplication, QWidget, QLabel
import sys
# 1. 创建应用实例(每个 PyQt 程序必须有且只有一个 QApplication)
app = QApplication(sys.argv)
# 2. 创建主窗口
window = QWidget()
window.setWindowTitle("我的第一个 PyQt6 应用") # 设置窗口标题
window.resize(400, 300) # 设置窗口大小(宽 x 高)
# 3. 添加组件(标签)
label = QLabel("Hello PyQt6!", parent=window)
label.move(150, 130) # 设置组件位置(x,y)
# 4. 显示窗口
window.show()
# 5. 启动应用事件循环
sys.exit(app.exec())
一个标准的 PyQt6 程序包含 5 个核心步骤,所有复杂应用都基于此扩展:
parent 参数指定所属容器;show() 方法让组件可见;app.exec() 让程序进入循环,等待用户操作(如点击、输入)。PyQt6 提供了上百种组件,以下是最常用的 10 种核心组件,每种都包含'功能说明 + 代码示例 + 参数解析',可直接套用。
窗口是应用的容器,PyQt6 中常用 QWidget(基础窗口)和 QMainWindow(带菜单栏/工具栏的主窗口)。
from PyQt6.QtWidgets import QApplication, QWidget
from PyQt6.QtGui import QIcon
import sys
app = QApplication(sys.argv)
# 创建基础窗口
window = QWidget()
window.setWindowTitle("PyQt6 窗口示例") # 窗口标题
window.resize(500, 400) # 窗口大小
window.move(100, 100) # 窗口初始位置(屏幕左上角为原点)
window.setFixedSize(500, 400) # 禁止调整窗口大小
# 设置窗口图标(需.ico 格式文件)
# window.setWindowIcon(QIcon("icon.ico"))
# 显示窗口
window.show()
sys.exit(app.exec())
from PyQt6.QtWidgets import QApplication, QMainWindow
import sys
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("QMainWindow 示例")
self.resize(500, 400)
# 设置中心组件(QMainWindow 必须通过中心组件添加内容)
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
QLabel 用于显示静态文本、图片或富文本,是最基础的展示组件。
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout
from PyQt6.QtCore import Qt
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("QLabel 示例")
window.resize(300, 200)
# 创建布局(后续详解)
layout = QVBoxLayout(window)
# 1. 普通文本标签
label1 = QLabel("普通文本标签")
label1.setStyleSheet("font-size: 14px; color: #333;")
layout.addWidget(label1)
# 2. 富文本标签(支持 HTML 格式)
label2 = QLabel('<font color="red" size="5">富文本标签</font>')
layout.addWidget(label2)
# 3. 居中对齐的标签
label3 = QLabel("居中对齐的标签")
label3.setAlignment(Qt.AlignmentFlag.AlignCenter) # 居中对齐
label3.setStyleSheet("background-color: #f0f0f0; padding: 10px;")
layout.addWidget(label3)
window.show()
sys.exit(app.exec())
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout
from PyQt6.QtGui import QPixmap
from PyQt6.QtCore import Qt
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("显示图片")
window.resize(300, 300)
layout = QVBoxLayout(window)
# 创建图片标签
label = QLabel()
# 加载图片(支持 jpg、png 等格式)
pixmap = QPixmap("test.jpg") # 替换为你的图片路径
# 缩放图片以适应标签大小
pixmap = pixmap.scaled(200, 200)
label.setPixmap(pixmap)
label.setAlignment(Qt.AlignmentFlag.AlignCenter) # 图片居中
layout.addWidget(label)
window.show()
sys.exit(app.exec())
QPushButton 是最常用的交互组件,用户点击后会触发预设的功能逻辑。
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QMessageBox
from PyQt6.QtCore import Qt
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("QPushButton 示例")
window.resize(300, 200)
layout = QVBoxLayout(window)
# 定义按钮点击事件的处理函数
def on_button_click():
QMessageBox.information(window, "提示", "你点击了按钮!") # 弹出信息框
# 创建按钮
button = QPushButton("点击我")
button.setStyleSheet("""
QPushButton { font-size: 14px; padding: 8px 16px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; }
QPushButton:hover { background-color: #45a049; }
""") # 自定义按钮样式(hover 为鼠标悬浮效果)
button.clicked.connect(on_button_click) # 绑定点击事件
layout.addWidget(button, alignment=Qt.AlignmentFlag.AlignCenter)
window.show()
sys.exit(app.exec())
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout
from PyQt6.QtGui import QIcon
from PyQt6.QtCore import QtCore
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("按钮进阶示例")
window.resize(300, 100)
layout = QHBoxLayout(window)
layout.setSpacing(20) # 组件间距
# 1. 带图标的按钮
icon_button = QPushButton()
icon_button.setIcon(QIcon("icon.png")) # 设置图标
icon_button.setIconSize(QtCore.QSize(32, 32)) # 图标大小
layout.addWidget(icon_button)
# 2. 禁用状态的按钮
disabled_button = QPushButton("禁用按钮")
disabled_button.setDisabled(True) # 禁用按钮
layout.addWidget(disabled_button)
# 3. 切换按钮状态
toggle_button = QPushButton("切换状态")
toggle_button.setCheckable(True) # 可勾选状态
def on_toggle(state):
print(f"按钮状态:{'勾选' if state else '未勾选'}")
toggle_button.toggled.connect(on_toggle) # 绑定状态切换事件
layout.addWidget(toggle_button)
window.show()
sys.exit(app.exec())
QLineEdit 用于接收用户的单行文本输入(如用户名、密码、搜索关键词),支持输入验证和格式限制。
from PyQt6.QtWidgets import QApplication, QWidget, QLineEdit, QLabel, QVBoxLayout, QPushButton, QMessageBox
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("登录窗口")
window.resize(300, 250)
layout = QVBoxLayout(window)
layout.setSpacing(15)
layout.setContentsMargins(30, 30, 30, 30) # 内边距
# 用户名标签和输入框
user_label = QLabel("用户名:")
user_label.setStyleSheet("font-size: 14px;")
layout.addWidget(user_label)
user_edit = QLineEdit()
user_edit.setPlaceholderText("请输入用户名") # 提示文本
user_edit.setStyleSheet("font-size: 14px; padding: 8px;")
layout.addWidget(user_edit)
# 密码标签和输入框
pwd_label = QLabel("密码:")
pwd_label.setStyleSheet("font-size: 14px;")
layout.addWidget(pwd_label)
pwd_edit = QLineEdit()
pwd_edit.setPlaceholderText("请输入密码")
pwd_edit.setEchoMode(QLineEdit.EchoMode.Password) # 密码隐藏模式
pwd_edit.setStyleSheet("font-size: 14px; padding: 8px;")
layout.addWidget(pwd_edit)
# 登录按钮
def login():
username = user_edit.text().strip()
password = pwd_edit.text().strip()
if username == "admin" and password == "123456":
QMessageBox.information(window, "成功", "登录成功!")
else:
QMessageBox.warning(window, "错误", "用户名或密码错误!")
login_btn = QPushButton("登录")
login_btn.setStyleSheet("""
QPushButton { font-size: 14px; padding: 10px; background-color: #2196F3; color: white; border: none; border-radius: 4px; }
""")
login_btn.clicked.connect(login)
layout.addWidget(login_btn)
window.show()
sys.exit(app.exec())
QTextEdit 支持多行文本输入和编辑,可用于显示日志、编辑文档等场景,支持富文本格式。
from PyQt6.QtWidgets import QApplication, QWidget, QTextEdit, QPushButton, QVBoxLayout, QMessageBox
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("QTextEdit 示例")
window.resize(400, 300)
layout = QVBoxLayout(window)
# 创建文本框
text_edit = QTextEdit()
text_edit.setPlaceholderText("请输入多行文本...")
text_edit.setStyleSheet("font-size: 14px; padding: 10px;")
# 插入默认文本(支持富文本)
text_edit.insertHtml("<font color='blue'>这是默认的富文本内容</font>")
layout.addWidget(text_edit)
# 按钮:获取文本内容
def get_text():
# 获取纯文本
plain_text = text_edit.toPlainText()
# 获取富文本
html_text = text_edit.toHtml()
QMessageBox.information(window, "文本内容", f"纯文本:\n{plain_text}\n\n富文本:\n{html_text[:100]}...")
get_btn = QPushButton("获取文本")
get_btn.clicked.connect(get_text)
layout.addWidget(get_btn)
window.show()
sys.exit(app.exec())
QCheckBox 用于实现多选功能,用户可勾选多个选项,常用于设置偏好、选择兴趣等场景。
from PyQt6.QtWidgets import QApplication, QWidget, QCheckBox, QPushButton, QVBoxLayout, QLabel
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("QCheckBox 示例")
window.resize(300, 200)
layout = QVBoxLayout(window)
# 定义变量存储选择结果
hobbies = []
# 复选框:编程
cb1 = QCheckBox("编程")
cb1.setStyleSheet("font-size: 14px;")
layout.addWidget(cb1)
# 复选框:阅读
cb2 = QCheckBox("阅读")
cb2.setStyleSheet("font-size: 14px;")
layout.addWidget(cb2)
# 复选框:运动
cb3 = QCheckBox("运动")
cb3.setStyleSheet("font-size: 14px;")
layout.addWidget(cb3)
# 显示选择结果
result_label = QLabel("你的兴趣:")
result_label.setStyleSheet("font-size: 14px; margin-top: 10px;")
layout.addWidget(result_label)
def show_result():
hobbies.clear()
if cb1.isChecked(): hobbies.append(cb1.text())
if cb2.isChecked(): hobbies.append(cb2.text())
if cb3.isChecked(): hobbies.append(cb3.text())
result_label.setText(f"你的兴趣:{'、'.join(hobbies) if hobbies else '无'}")
# 绑定状态变化事件
cb1.stateChanged.connect(show_result)
cb2.stateChanged.connect(show_result)
cb3.stateChanged.connect(show_result)
window.show()
sys.exit(app.exec())
QRadioButton 用于实现单选功能,同一组中只能勾选一个选项,常用于选择性别、学历等场景。
from PyQt6.QtWidgets import QApplication, QWidget, QRadioButton, QVBoxLayout, QLabel, QGroupBox
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("QRadioButton 示例")
window.resize(300, 200)
layout = QVBoxLayout(window)
# 创建分组框(将单选按钮分组,确保互斥)
group_box = QGroupBox("选择性别")
group_box.setStyleSheet("font-size: 14px;")
group_layout = QVBoxLayout(group_box)
# 单选按钮:男
rb1 = QRadioButton("男")
rb1.setStyleSheet("font-size: 14px;")
rb1.setChecked(True) # 默认勾选
group_layout.addWidget(rb1)
# 单选按钮:女
rb2 = QRadioButton("女")
rb2.setStyleSheet("font-size: 14px;")
group_layout.addWidget(rb2)
layout.addWidget(group_box)
# 显示选择结果
result_label = QLabel("你的性别:男")
result_label.setStyleSheet("font-size: 14px; margin-top: 10px;")
layout.addWidget(result_label)
def show_gender():
if rb1.isChecked():
result_label.setText("你的性别:男")
else:
result_label.setText("你的性别:女")
# 绑定状态变化事件
rb1.toggled.connect(show_gender)
rb2.toggled.connect(show_gender)
window.show()
sys.exit(app.exec())
QComboBox 提供下拉选择列表,用户从预设选项中选择一个,常用于选择城市、年级、文件类型等场景。
from PyQt6.QtWidgets import QApplication, QWidget, QComboBox, QVBoxLayout, QLabel
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("QComboBox 示例")
window.resize(300, 200)
layout = QVBoxLayout(window)
# 创建下拉菜单
combo = QComboBox()
combo.setStyleSheet("font-size: 14px; padding: 8px;")
# 添加选项
combo.addItems(["北京", "上海", "广州", "深圳", "杭州"])
# 设置默认选项(索引从 0 开始)
combo.setCurrentIndex(0)
layout.addWidget(combo)
# 显示选择结果
result_label = QLabel(f"你选择的城市:{combo.currentText()}")
result_label.setStyleSheet("font-size: 14px; margin-top: 20px;")
layout.addWidget(result_label)
# 绑定选项变化事件
def on_combo_change(index):
result_label.setText(f"你选择的城市:{combo.itemText(index)}")
combo.currentIndexChanged.connect(on_combo_change)
window.show()
sys.exit(app.exec())
QSlider 用于让用户通过拖动滑块调节数值,常用于调节音量、亮度、字体大小等场景。
from PyQt6.QtWidgets import QApplication, QWidget, QSlider, QVBoxLayout, QLabel
from PyQt6.QtCore import Qt
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("QSlider 示例")
window.resize(300, 200)
layout = QVBoxLayout(window)
# 创建滑块(水平方向)
slider = QSlider(Qt.Orientation.Horizontal)
slider.setRange(10, 30) # 数值范围
slider.setValue(14) # 默认值
slider.setSingleStep(1) # 步长
layout.addWidget(slider)
# 显示调节结果
label = QLabel("当前字体大小:14px")
label.setStyleSheet("font-size: 14px; margin-top: 20px;")
layout.addWidget(label)
# 绑定滑块值变化事件
def on_slider_change(value):
label.setText(f"当前字体大小:{value}px")
label.setStyleSheet(f"font-size: {value}px; margin-top: 20px;")
slider.valueChanged.connect(on_slider_change)
window.show()
sys.exit(app.exec())
QListWidget 用于展示单列列表数据,支持单选、多选和双击事件,常用于展示文件列表、选项列表等。
from PyQt6.QtWidgets import QApplication, QWidget, QListWidget, QListWidgetItem, QVBoxLayout, QLabel
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("QListWidget 示例")
window.resize(300, 200)
layout = QVBoxLayout(window)
# 创建列表框
list_widget = QListWidget()
list_widget.setStyleSheet("font-size: 14px;")
# 设置选择模式:多选
list_widget.setSelectionMode(QListWidget.SelectionMode.MultiSelection)
# 添加列表项
items = ["文件 1.txt", "文件 2.jpg", "文件 3.pdf", "文件 4.exe"]
for item_text in items:
QListWidgetItem(item_text, list_widget)
layout.addWidget(list_widget)
# 显示选择结果
result_label = QLabel("你选择的文件:无")
result_label.setStyleSheet("font-size: 14px; margin-top: 10px;")
layout.addWidget(result_label)
# 绑定选择变化事件
def on_list_select():
selected_items = list_widget.selectedItems()
selected_texts = [item.text() for item in selected_items]
result_label.setText(f"你选择的文件:{'、'.join(selected_texts) if selected_texts else '无'}")
list_widget.itemSelectionChanged.connect(on_list_select)
window.show()
sys.exit(app.exec())
PyQt6 提供三种核心布局方式,用于控制组件在窗口中的位置和大小,避免手动计算坐标的繁琐,确保窗口大小变化时组件能自适应调整。
QVBoxLayout 将组件按垂直方向依次排列,适合需要上下布局的场景(如表单、列表)。
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QVBoxLayout
from PyQt6.QtCore import Qt
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("QVBoxLayout 示例")
window.resize(300, 250)
# 创建垂直布局
layout = QVBoxLayout(window)
layout.setSpacing(15) # 组件之间的间距
layout.setContentsMargins(20, 20, 20, 20) # 布局与窗口的内边距
# 添加组件
layout.addWidget(QLabel("用户名:"))
layout.addWidget(QLineEdit())
layout.addWidget(QLabel("密码:"))
layout.addWidget(QLineEdit())
layout.addWidget(QLabel("邮箱:"))
layout.addWidget(QLineEdit())
# 按钮:添加到布局底部,居中对齐
login_btn = QPushButton("注册")
layout.addWidget(login_btn, alignment=Qt.AlignmentFlag.AlignCenter)
window.show()
sys.exit(app.exec())
QHBoxLayout 将组件按水平方向依次排列,适合需要左右布局的场景(如工具栏、按钮组)。
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("QHBoxLayout 示例")
window.resize(300, 100)
# 创建水平布局
layout = QHBoxLayout(window)
layout.setSpacing(10)
layout.setContentsMargins(20, 20, 20, 20)
# 添加按钮
layout.addWidget(QPushButton("新建"))
layout.addWidget(QPushButton("打开"))
layout.addWidget(QPushButton("保存"))
layout.addWidget(QPushButton("退出"))
# 设置组件拉伸比例(让按钮自适应窗口宽度)
layout.setStretch(0, 1)
layout.setStretch(1, 1)
layout.setStretch(2, 1)
layout.setStretch(3, 1)
window.show()
sys.exit(app.exec())
QGridLayout 将组件按'行 × 列'的表格形式排列,适合复杂的界面布局(如登录窗口、数据表格)。
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QGridLayout, QMessageBox
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("QGridLayout 示例")
window.resize(300, 200)
# 创建网格布局
layout = QGridLayout(window)
layout.setSpacing(15)
layout.setContentsMargins(30, 30, 30, 30)
# 添加组件(行索引,列索引,跨行数,跨列数)
layout.addWidget(QLabel("用户名:"), 0, 0)
layout.addWidget(QLineEdit(), 0, 1, 1, 2) # 第 0 行第 1 列,跨 2 列
layout.addWidget(QLabel("密码:"), 1, 0)
layout.addWidget(QLineEdit(), 1, 1, 1, 2) # 第 1 行第 1 列,跨 2 列
# 登录按钮:第 2 行第 1-2 列,跨 2 列
login_btn = QPushButton("登录")
login_btn.clicked.connect(lambda: QMessageBox.information(window, "提示", "登录中..."))
layout.addWidget(login_btn, 2, 1, 1, 2)
window.show()
sys.exit(app.exec())
实际开发中,常将多种布局嵌套使用,实现更灵活的界面布局。
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout, QHBoxLayout
from PyQt6.QtCore import Qt
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("布局嵌套示例")
window.resize(400, 300)
# 主布局:垂直布局
main_layout = QVBoxLayout(window)
# 顶部区域:水平布局(标题 + 按钮)
top_layout = QHBoxLayout()
top_layout.addWidget(QLabel("复杂界面布局示例"), alignment=Qt.AlignmentFlag.AlignLeft)
top_layout.addWidget(QPushButton("设置"), alignment=Qt.AlignmentFlag.AlignRight)
main_layout.addLayout(top_layout)
# 中间区域:网格布局(表单)
grid_layout = QGridLayout()
grid_layout.addWidget(QLabel("姓名:"), 0, 0)
grid_layout.addWidget(QLineEdit(), 0, 1)
grid_layout.addWidget(QLabel("年龄:"), 1, 0)
grid_layout.addWidget(QLineEdit(), 1, 1)
main_layout.addLayout(grid_layout)
# 底部区域:水平布局(功能按钮)
bottom_layout = QHBoxLayout()
bottom_layout.addWidget(QPushButton("确定"))
bottom_layout.addWidget(QPushButton("取消"))
main_layout.addLayout(bottom_layout, alignment=Qt.AlignmentFlag.AlignCenter)
window.show()
sys.exit(app.exec())
PyQt6 的交互核心是'信号与槽(Signal and Slot)'机制,组件的动作(如点击、输入、选择)会发出'信号',开发者通过绑定'槽函数'来响应这些信号,实现交互逻辑。
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout
import sys
app = QApplication(sys.argv)
window = QWidget()
window.resize(300, 200)
layout = QVBoxLayout(window)
# 定义槽函数
def on_click():
print("按钮被点击了!")
# 创建按钮,绑定信号与槽
btn = QPushButton("点击我")
btn.clicked.connect(on_click) # clicked 是信号,connect 绑定槽函数
layout.addWidget(btn)
window.show()
sys.exit(app.exec())
from PyQt6.QtWidgets import QApplication, QWidget, QSlider, QVBoxLayout, QLabel
from PyQt6.QtCore import Qt
import sys
app = QApplication(sys.argv)
window = QWidget()
window.resize(300, 200)
layout = QVBoxLayout(window)
label = QLabel("当前值:50")
layout.addWidget(label)
# 带参数的槽函数
def on_value_change(value):
label.setText(f"当前值:{value}")
# 滑块值变化信号(带参数)绑定槽函数
slider = QSlider(Qt.Orientation.Horizontal)
slider.setRange(0, 100)
slider.setValue(50)
slider.valueChanged.connect(on_value_change) # valueChanged 信号传递数值参数
layout.addWidget(slider)
window.show()
sys.exit(app.exec())
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout
import sys
app = QApplication(sys.argv)
window = QWidget()
window.resize(300, 200)
layout = QVBoxLayout(window)
def on_click():
print("按钮被点击了!")
# 解除绑定,后续点击不再触发
btn = QPushButton("点击一次")
btn.clicked.connect(on_click)
layout.addWidget(btn)
window.show()
sys.exit(app.exec())
| 组件 | 信号名称 | 说明 |
|---|---|---|
| QPushButton | clicked() | 按钮被点击时发出 |
| QLineEdit | textChanged(text) | 文本内容变化时发出(带文本参数) |
| QCheckBox | stateChanged(state) | 勾选状态变化时发出(带状态参数) |
| QRadioButton | toggled(checked) | 勾选状态变化时发出(带布尔参数) |
| QComboBox | currentIndexChanged(index) | 选择项变化时发出(带索引参数) |
| QSlider | valueChanged(value) | 滑块值变化时发出(带数值参数) |
| QListWidget | itemClicked(item) | 列表项被点击时发出(带项参数) |
除了组件自带的信号,还可以自定义信号,实现更灵活的事件传递。
from PyQt6.QtCore import QObject, pyqtSignal
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout
import sys
# 自定义信号类(必须继承 QObject)
class MySignal(QObject):
# 定义自定义信号(可带参数)
custom_signal = pyqtSignal(str)
app = QApplication(sys.argv)
window = QWidget()
window.resize(300, 200)
layout = QVBoxLayout(window)
# 创建信号实例
signal = MySignal()
# 定义槽函数
def on_custom_signal(msg):
print(f"收到自定义信号:{msg}")
# 绑定自定义信号与槽
signal.custom_signal.connect(on_custom_signal)
# 按钮点击时发射自定义信号
def send_signal():
signal.custom_signal.emit("Hello, 自定义信号!")
btn = QPushButton("发射信号")
btn.clicked.connect(send_signal)
layout.addWidget(btn)
window.show()
sys.exit(app.exec())
菜单和工具栏是桌面应用的标准组件,用于组织核心功能(如文件操作、编辑功能)。
from PyQt6.QtWidgets import QApplication, QMainWindow, QTextEdit, QAction, QFileDialog, QMessageBox
from PyQt6.QtGui import QIcon
import sys
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("菜单与工具栏示例")
self.resize(600, 400)
# 设置中心组件(文本编辑区)
self.text_edit = QTextEdit()
self.setCentralWidget(self.text_edit)
# 创建菜单
self.create_menu()
# 创建工具栏
self.create_toolbar()
def create_menu(self):
# 获取主菜单栏
menu_bar = self.menuBar()
# 文件菜单
file_menu = menu_bar.addMenu("文件")
# 新建动作
new_action = QAction(QIcon("new.png"), "新建", self)
new_action.setShortcut("Ctrl+N") # 快捷键
new_action.triggered.connect(self.new_file)
file_menu.addAction(new_action)
# 打开动作
open_action = QAction(QIcon("open.png"), "打开", self)
open_action.setShortcut("Ctrl+O")
open_action.triggered.connect(self.open_file)
file_menu.addAction(open_action)
# 保存动作
save_action = QAction(QIcon("save.png"), "保存", self)
save_action.setShortcut("Ctrl+S")
save_action.triggered.connect(self.save_file)
file_menu.addAction(save_action)
# 分隔线
file_menu.addSeparator()
# 退出动作
exit_action = QAction("退出", self)
exit_action.setShortcut("Ctrl+Q")
exit_action.triggered.connect(self.close)
file_menu.addAction(exit_action)
def create_toolbar(self):
# 创建工具栏
toolbar = self.addToolBar("工具栏")
# 添加动作(与菜单动作共用)
new_action = QAction(QIcon("new.png"), "新建", self)
new_action.triggered.connect(self.new_file)
toolbar.addAction(new_action)
open_action = QAction(QIcon("open.png"), "打开", self)
open_action.triggered.connect(self.open_file)
toolbar.addAction(open_action)
save_action = QAction(QIcon("save.png"), "保存", self)
save_action.triggered.connect(self.save_file)
toolbar.addAction(save_action)
def new_file(self):
self.text_edit.clear()
self.setWindowTitle("未命名文件")
def open_file(self):
file_path, _ = QFileDialog.getOpenFileName(self, "打开文件", "", "文本文件 (*.txt)")
if file_path:
with open(file_path, "r", encoding="utf-8") as f:
self.text_edit.setText(f.read())
self.setWindowTitle(file_path)
def save_file(self):
file_path, _ = QFileDialog.getSaveFileName(self, "保存文件", "", "文本文件 (*.txt)")
if file_path:
with open(file_path, "w", encoding="utf-8") as f:
f.write(self.text_edit.toPlainText())
self.setWindowTitle(file_path)
QMessageBox.information(self, "提示", "保存成功!")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
PyQt6 提供多种内置对话框,用于显示提示、警告、确认信息,或获取用户输入、选择文件等。
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QMessageBox, QFileDialog, QInputDialog
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("对话框示例")
window.resize(300, 200)
layout = QVBoxLayout(window)
# 1. 信息对话框
def show_info():
QMessageBox.information(window, "信息", "这是一条信息提示!")
# 2. 警告对话框
def show_warning():
QMessageBox.warning(window, "警告", "这是一条警告信息!")
# 3. 确认对话框
def show_confirm():
result = QMessageBox.question(window, "确认", "你确定要退出吗?", QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
if result == QMessageBox.StandardButton.Yes:
window.close()
# 4. 文件选择对话框
def select_file():
file_path, _ = QFileDialog.getOpenFileName(window, "选择文件", "", "所有文件 (*.*)")
QMessageBox.information(window, "选择结果", f"你选择的文件:{file_path}")
# 5. 输入对话框
def input_text():
text, ok = QInputDialog.getText(window, "输入", "请输入你的名字:")
if ok and text:
QMessageBox.information(window, "问候", f"你好,{text}!")
# 添加按钮
layout.addWidget(QPushButton("信息框", clicked=show_info))
layout.addWidget(QPushButton("警告框", clicked=show_warning))
layout.addWidget(QPushButton("确认框", clicked=show_confirm))
layout.addWidget(QPushButton("选择文件", clicked=select_file))
layout.addWidget(QPushButton("输入框", clicked=input_text))
window.show()
sys.exit(app.exec())
当应用执行耗时操作(如文件下载、数据处理)时,若在主线程中执行,会导致界面冻结无响应。解决方法是将耗时操作放在子线程中执行。
from PyQt6.QtCore import QThread, pyqtSignal
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QProgressBar, QLabel
import sys
import time
# 自定义子线程类
class WorkerThread(QThread):
# 定义信号(传递进度值)
progress_signal = pyqtSignal(int)
# 任务完成信号
finish_signal = pyqtSignal()
def run(self):
# 模拟耗时任务(10 秒完成,每 1 秒更新一次进度)
for i in range(1, 11):
time.sleep(1)
self.progress_signal.emit(i * 10) # 发送进度信号
self.finish_signal.emit() # 发送完成信号
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("多线程示例")
window.resize(300, 200)
layout = QVBoxLayout(window)
# 进度条
progress_bar = QProgressBar()
progress_bar.setRange(0, 100)
layout.addWidget(progress_bar)
# 状态标签
status_label = QLabel("等待任务开始...")
layout.addWidget(status_label)
# 开始按钮
def start_task():
btn.setEnabled(False)
status_label.setText("任务执行中...")
# 创建并启动子线程
thread = WorkerThread()
thread.progress_signal.connect(update_progress)
thread.finish_signal.connect(task_finish)
thread.start()
def update_progress(value):
progress_bar.setValue(value)
def task_finish():
status_label.setText("任务完成!")
btn.setEnabled(True)
btn = QPushButton("开始耗时任务")
btn.clicked.connect(start_task)
layout.addWidget(btn)
window.show()
sys.exit(app.exec())
QSS(Qt Style Sheet)是 PyQt6 的样式表语言,类似 CSS,可自定义组件的外观,打造现代化界面。
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout, QLineEdit
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("QSS 美化示例")
window.resize(300, 250)
# 设置全局 QSS 样式
window.setStyleSheet("""
QWidget { background-color: #f5f5f5; }
QLabel { font-size: 14px; color: #333; }
QLineEdit { font-size: 14px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; background-color: white; }
QLineEdit:focus { border-color: #2196F3; outline: none; }
QPushButton { font-size: 14px; padding: 10px; background-color: #2196F3; color: white; border: none; border-radius: 4px; }
QPushButton:hover { background-color: #1976D2; }
QPushButton:pressed { background-color: #0D47A1; }
""")
layout = QVBoxLayout(window)
layout.setSpacing(15)
layout.setContentsMargins(30, 30, 30, 30)
layout.addWidget(QLabel("用户名:"))
layout.addWidget(QLineEdit())
layout.addWidget(QLabel("密码:"))
layout.addWidget(QLineEdit())
layout.addWidget(QPushButton("登录"))
window.show()
sys.exit(app.exec())
当内置组件无法满足需求时,可通过继承现有组件自定义新组件,实现个性化功能。
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QHBoxLayout
import sys
# 自定义计数器组件
class CounterWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.count = 0
self.init_ui()
def init_ui(self):
# 布局
layout = QHBoxLayout(self)
layout.setSpacing(10)
# 减号按钮
self.minus_btn = QPushButton("-")
self.minus_btn.clicked.connect(self.decrement)
layout.addWidget(self.minus_btn)
# 计数标签
self.count_label = QLabel("0")
self.count_label.setStyleSheet("font-size: 16px; width: 40px; text-align: center;")
layout.addWidget(self.count_label)
# 加号按钮
self.plus_btn = QPushButton("+")
self.plus_btn.clicked.connect(self.increment)
layout.addWidget(self.plus_btn)
def increment(self):
self.count += 1
self.count_label.setText(str(self.count))
def decrement(self):
if self.count > 0:
self.count -= 1
self.count_label.setText(str(self.count))
# 测试自定义组件
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("自定义组件示例")
window.resize(200, 100)
layout = QHBoxLayout(window)
layout.addWidget(CounterWidget())
layout.addWidget(CounterWidget())
window.show()
sys.exit(app.exec())
结合前面的知识点,开发一个简易计算器应用,支持加减乘除四则运算,整合组件、布局、事件处理等核心功能。
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QLineEdit, QGridLayout, QPushButton
from PyQt6.QtCore import Qt
import sys
class Calculator(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("简易计算器")
self.resize(300, 400)
self.setFixedSize(300, 400) # 禁止调整大小
# 初始化计算状态
self.current_text = "" # 当前输入文本
self.result = 0 # 计算结果
self.operator = "" # 运算符
self.reset_display = False # 是否重置显示
# 设置中心组件
central_widget = QWidget()
self.setCentralWidget(central_widget)
# 创建布局
self.layout = QGridLayout(central_widget)
self.layout.setSpacing(5)
self.layout.setContentsMargins(10, 10, 10, 10)
# 创建显示框
self.create_display()
# 创建按钮
self.create_buttons()
def create_display(self):
# 显示框(只读)
self.display = QLineEdit()
self.display.setReadOnly(True)
self.display.setStyleSheet("""
QLineEdit { font-size: 24px; padding: 10px; text-align: right; background-color: #f9f9f9; border: 1px solid #ddd; border-radius: 4px; }
""")
self.display.setText("0") # 显示框占第一行,跨 4 列
self.layout.addWidget(self.display, 0, 0, 1, 4)
def create_buttons(self):
# 按钮布局(5 行 4 列)
buttons = [
["AC", "±", "%", "÷"],
["7", "8", "9", "×"],
["4", "5", "6", "-"],
["1", "2", "3", "+"],
["0", ".", "←", "="]
]
# 按钮样式
btn_style = """
QPushButton { font-size: 18px; padding: 15px; border: none; border-radius: 4px; }
QPushButton:hover { background-color: #e0e0e0; }
"""
# 运算符按钮样式
op_btn_style = btn_style + "background-color: #ff9500; color: white;"
# 数字按钮样式
num_btn_style = btn_style + "background-color: #f2f2f2;"
# 等号按钮样式
eq_btn_style = btn_style + "background-color: #ff5722; color: white;"
# 添加按钮到布局
for row in range(len(buttons)):
for col in range(len(buttons[row])):
btn_text = buttons[row][col]
btn = QPushButton(btn_text)
# 设置按钮样式
if btn_text in ["+", "-", "×", "÷"]:
btn.setStyleSheet(op_btn_style)
elif btn_text == "=":
btn.setStyleSheet(eq_btn_style)
else:
btn.setStyleSheet(num_btn_style)
# 绑定点击事件
btn.clicked.connect(lambda checked, text=btn_text: self.on_button_click(text))
# 添加到布局
self.layout.addWidget(btn, row+1, col) # 行从 1 开始(第 0 行是显示框)
def on_button_click(self, text):
if text == "AC": # 清空
self.current_text = ""
self.result = 0
self.operator = ""
self.display.setText("0")
elif text == "±": # 正负号
if self.current_text.startswith("-"):
self.current_text = self.current_text[1:]
else:
self.current_text = "-" + self.current_text
if self.current_text:
self.display.setText(self.current_text)
elif text == "%": # 百分比
if self.current_text:
value = float(self.current_text) / 100
self.current_text = str(value)
self.display.setText(self.current_text)
elif text == "←": # 删除
self.current_text = self.current_text[:-1]
self.display.setText(self.current_text if self.current_text else "0")
elif text in ["+", "-", "×", "÷"]: # 运算符
if self.current_text:
self.result = float(self.current_text)
self.operator = text
self.current_text = ""
self.reset_display = True
elif text == "=": # 计算结果
if self.current_text and self.operator:
current_value = float(self.current_text)
if self.operator == "+":
self.result += current_value
elif self.operator == "-":
self.result -= current_value
elif self.operator == "×":
self.result *= current_value
elif self.operator == "÷":
if current_value != 0:
self.result /= current_value
else:
self.display.setText("错误")
return
# 结果转为字符串,去除末尾的.0
self.current_text = str(int(self.result)) if self.result.is_integer() else str(self.result)
self.display.setText(self.current_text)
self.operator = ""
self.reset_display = True
elif text == ".": # 小数点
if "." not in self.current_text:
self.current_text += "."
self.display.setText(self.current_text)
else: # 数字
if self.reset_display:
self.current_text = text
self.reset_display = False
else:
self.current_text += text
self.display.setText(self.current_text)
if __name__ == "__main__":
app = QApplication(sys.argv)
calculator = Calculator()
calculator.show()
sys.exit(app.exec())
app = QApplication(sys.argv)。parent 参数,会导致组件无法显示。解决:将组件添加到布局,或创建时指定 parent=window。setStyleSheet 直接给组件设置样式。sys.exit(app.exec()) 启动事件循环,确保窗口关闭时程序退出。PyQt6 的学习核心是'多动手实践'——从简单组件开始,逐步搭建复杂界面,结合实际需求开发工具,遇到问题时查阅官方文档(https://doc.qt.io/qtforpython/)。它虽然学习曲线比 Tkinter 陡,但掌握后能开发出专业级的桌面应用,是 Python 开发者提升竞争力的重要技能。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online