QtWidgets是 PyQt5 中用于构建经典桌面风格界面的核心模块。你可以把它想象成一个“GUI控件百宝箱”,里面包含了创建窗口、按钮、文本框、表格等所有你需要的可视化组件。
它的核心思想是面向对象的,所有可视元素都继承自QWidget基类,使得界面元素的组合和扩展非常灵活。
基石:三种核心窗口类
在QtWidgets中,有三种最基础的窗口类,它们是任何PyQt5应用的起点:
QWidget:所有用户界面元素的基类。它像一个“空白画布”,自由度最高,允许你从零开始构建任何样式的界面。QMainWindow:主应用程序窗口。它继承自QWidget,并预置了菜单栏(QMenuBar)、工具栏(QToolBar)、状态栏(QStatusBar) 和中央区域(centralWidget)。适合创建带有完整框架的复杂应用。QDialog:对话框窗口的基类。通常用于执行短期任务或与用户进行一次性交互,比如文件选择、消息提示或设置窗口。
常用控件一览
QtWidgets提供了丰富的现成控件,可以满足大部分界面需求。以下是一些最常用的:
布局管理:让界面自适应
布局管理器负责自动调整子控件的位置和大小,以应对窗口尺寸的变化。推荐使用布局管理器,而不是通过setGeometry()进行绝对定位。
QHBoxLayout:水平布局,将子控件从左到右排列。QVBoxLayout:垂直布局,将子控件从上到下排列。QGridLayout:网格布局,以行和列的网格形式放置控件。QFormLayout:表单布局,专为“标签-字段”式的数据录入表单设计。
示例:创建一个包含标签和按钮的垂直布局窗口。
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("布局示例")
# 1. 创建控件
self.label = QLabel("Hello, PyQt5!")
self.button = QPushButton("点击我")
# 2. 创建布局管理器
layout = QVBoxLayout()
# 3. 将控件添加到布局中
layout.addWidget(self.label)
layout.addWidget(self.button)
# 4. 将布局设置为窗口的主布局
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
信号与槽:交互的“连接线”
信号与槽是PyQt5对象间通信的核心机制。简单说,信号就是一个“事件”(如按钮被点击),而槽就是响应这个事件的“函数”。
基础用法:
定义槽函数:编写一个普通的Python函数来处理事件。
连接信号与槽:使用
信号.connect(槽函数)将两者绑定
注意事项:
对象树与内存管理:创建控件时指定父对象(如
QLabel(self)),PyQt5 会自动管理其生命周期,父对象销毁时子对象也会被销毁,有效防止内存泄漏。样式表(QSS)的作用域:为父控件设置样式表会影响所有子控件。为避免“污染”,应使用ID选择器(如
#myButton)或类选择器来限定样式的作用范围。避免界面卡顿:耗时的操作(如网络请求、大文件读写)应放在子线程中执行,否则会阻塞主线程(事件循环),导致界面“卡死”。
导入规范:通常使用
from PyQt5.QtWidgets import *导入所有控件,但为提升代码可读性,也可以按需导入特定的类。QApplication实例唯一:一个PyQt5程序有且只有一个QApplication实例,它管理着应用程序的控制流和主要设置。
=========================================================================
拓展介绍
1、高级组件与容器
2、模型/视图框架(Model/View)
对于大规模数据展示(如数据库记录、文件列表),直接使用QTableWidget、QListWidget等“便利类”会导致内存浪费和性能下降,因为它们会复制数据并维护每个单元格的控件。
模型/视图框架将数据存储(QAbstractItemModel)与数据显示(QListView、QTableView、QTreeView)分离,更高效、更灵活。
内置模型:
QStandardItemModel、QFileSystemModel、QSqlTableModel等。自定义模型:只需重写
rowCount()、columnCount()、data()等方法,即可与任意 Python 数据源对接。委托(Delegate):通过继承
QStyledItemDelegate可自定义单元格的编辑器(如弹出日期选择器)和绘制方式。
class MyTableModel(QAbstractTableModel):
def __init__(self, data):
super().__init__()
self._data = data
def rowCount(self, parent):
return len(self._data)
def columnCount(self, parent):
return len(self._data[0])
def data(self, index, role):
if role == Qt.DisplayRole:
return self._data[index.row()][index.column()]
视图与模型绑定后,数据更新只需调用模型的dataChanged等信号,视图会自动刷新。
3、样式定制与主题
Qt 样式表(QSS):语法类似 CSS,可精细定制控件外观(背景色、边框、圆角、渐变、伪状态
:hover、:pressed等)。建议为复杂应用定义全局样式表,保持视觉统一。QPalette:用于设置颜色组,但颗粒度不如 QSS 细。
自定义绘制:重写控件的
paintEvent()方法,实现任意图形绘制(如自定义进度条、图表等)。
最佳实践:将样式表保存在外部.qss文件中,运行时读取,便于切换主题。
4、多线程与界面通信
GUI 应用的主线程负责处理事件循环(响应鼠标点击、重绘等),任何耗时操作(网络请求、大文件读写、复杂计算)都会阻塞界面,导致“卡死”。正确做法:
使用
QThread创建工作线程,通过信号(pyqtSignal)将结果传回主线程更新 UI。使用
QThreadPool+QRunnable适用于轻量级并发任务。QTimer可用于定时刷新界面,但不可用于耗时任务。
class Worker(QThread):
result = pyqtSignal(str)
def run(self):
# 耗时操作
self.result.emit("完成")
# 在主窗口启动
self.worker = Worker()
self.worker.result.connect(self.update_label)
self.worker.start()
注意:子线程中禁止直接操作 GUI 控件,必须通过信号/槽机制。