3、PyQt5基础控件(下):QComboBox下拉框、QCheckBox复选框、QRadioButton单选框、QListWidget列表控件、QTableWidget表格控件
好,咱们接着聊。上一节我们把按钮、标签、输入框这些基础控件过了一遍,今天要讲的这几个,说实话,在真正的项目里出现频率极高。尤其是表格和列表,几乎每个带数据展示的桌面应用都离不开它们。
我个人习惯把今天的内容分成两类:一类是“选择型”控件,比如下拉框、复选框、单选框;另一类是“展示型”控件,比如列表和表格。这样分,你学起来思路会更清晰。
3.1 QComboBox 下拉框:省空间的利器
下拉框这东西,说白了就是一个节省界面空间的“选择器”。你想想看,如果让用户从 50 个城市里选一个,用一排按钮肯定不现实,用列表又占地方。下拉框就完美解决了这个问题——平时只显示一行,点击才展开。
我在项目中遇到过最典型的场景是“设置界面”。用户选择语言、主题、分辨率,几乎都用下拉框。嗯,这里要注意:下拉框的选项不要太多,超过 20 项建议加搜索功能,否则用户体验会下降。
from PyQt5.QtWidgets import QComboBox
combo = QComboBox()
combo.addItem("北京")
combo.addItem("上海")
combo.addItem("广州")
combo.addItem("深圳")
combo.addItem("杭州")
# 设置默认选中项
combo.setCurrentIndex(0)
# 获取当前选中文本
current_text = combo.currentText()
print(f"当前选择:{current_text}")
# 信号连接
combo.currentIndexChanged.connect(lambda idx: print(f"选中索引:{idx}"))
combo.setEditable(True) 即可。我经常在“自定义筛选”功能里用这个。
3.2 QCheckBox 复选框:多选场景的标配
复选框,就是那个小方框,打勾表示选中。它最常用的场景是“多选”,比如用户选择兴趣爱好、设置权限、勾选协议条款等。
我个人习惯把复选框的状态分为三种:选中、未选中、部分选中。部分选中这个状态很多人会忽略,但在树形结构或级联选择中非常有用。比如你有一个“全选”复选框,下面有多个子项,当子项部分选中时,父级复选框就应该显示为部分选中状态。
from PyQt5.QtWidgets import QCheckBox
cb = QCheckBox("我同意用户协议")
cb.setChecked(False) # 默认未选中
# 获取状态
if cb.isChecked():
print("已勾选")
else:
print("未勾选")
# 信号连接
cb.stateChanged.connect(lambda state: print(f"状态变化:{state}"))
# state: 0=未选中, 1=部分选中, 2=完全选中
setTristate(True) 可以开启三态模式。
3.3 QRadioButton 单选框:互斥选择的好帮手
单选框和复选框最大的区别是什么?单选框是“多选一”,复选框是“多选多”。单选框通常成组出现,同一组内只能选中一个。
你想想看,性别选择、支付方式、排序方式……这些场景用单框最合适。但要注意:单选框必须放在 QButtonGroup 里才能实现互斥,否则它们各自独立,互不影响。
from PyQt5.QtWidgets import QRadioButton, QButtonGroup
rb_male = QRadioButton("男")
rb_female = QRadioButton("女")
rb_other = QRadioButton("其他")
# 创建按钮组,实现互斥
gender_group = QButtonGroup()
gender_group.addButton(rb_male, 1) # id=1
gender_group.addButton(rb_female, 2) # id=2
gender_group.addButton(rb_other, 3) # id=3
# 默认选中
rb_male.setChecked(True)
# 获取选中按钮的 id
selected_id = gender_group.checkedId()
print(f"选中按钮 ID:{selected_id}")
# 信号连接
gender_group.buttonClicked[int].connect(
lambda btn_id: print(f"选中了 ID 为 {btn_id} 的按钮")
)
3.4 QListWidget 列表控件:轻量级数据展示
列表控件,说白了就是一个垂直排列的条目集合。它比下拉框更直观,因为所有选项都直接可见。适合选项数量不多(比如 5-15 项)且需要用户快速浏览的场景。
我记得有一次做文件管理器,左侧的目录树用 QTreeWidget,右侧的文件列表就用 QListWidget。用户点击左侧目录,右侧就刷新文件列表,体验非常好。
from PyQt5.QtWidgets import QListWidget, QListWidgetItem
list_widget = QListWidget()
list_widget.addItem("文档")
list_widget.addItem("图片")
list_widget.addItem("视频")
list_widget.addItem("音乐")
# 添加带图标的条目
item = QListWidgetItem("下载")
item.setIcon(QIcon("download.png")) # 需要导入 QIcon
list_widget.addItem(item)
# 设置当前选中项
list_widget.setCurrentRow(0)
# 信号连接
list_widget.currentItemChanged.connect(
lambda current, previous: print(f"当前选中:{current.text()}")
)
# 获取所有条目
for i in range(list_widget.count()):
item = list_widget.item(i)
print(f"第 {i} 项:{item.text()}")
list_widget.setSelectionMode(QAbstractItemView.MultiSelection)。我经常在批量操作功能里用这个。
3.5 QTableWidget 表格控件:结构化数据的王者
表格控件,这是今天最重量级的一个。它用来展示二维数据,比如学生成绩表、订单列表、库存清单等。说白了,就是 Excel 表格的简化版。
我在项目中用过很多次 QTableWidget,最头疼的是性能问题。如果你要展示几千行数据,直接用 QTableWidget 会卡死。这时候需要用 QTableView + 自定义模型。不过对于中小规模数据(几百行以内),QTableWidget 完全够用。
from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QHeaderView
table = QTableWidget()
table.setRowCount(5) # 5 行
table.setColumnCount(3) # 3 列
# 设置表头
table.setHorizontalHeaderLabels(["姓名", "年龄", "城市"])
# 填充数据
data = [
["张三", "25", "北京"],
["李四", "30", "上海"],
["王五", "28", "广州"],
["赵六", "22", "深圳"],
["孙七", "35", "杭州"]
]
for row, row_data in enumerate(data):
for col, value in enumerate(row_data):
item = QTableWidgetItem(value)
table.setItem(row, col, item)
# 自动调整列宽
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
# 设置交替行颜色(提升可读性)
table.setAlternatingRowColors(True)
# 信号连接
table.cellClicked.connect(lambda row, col: print(f"点击了第 {row} 行第 {col} 列"))
# 获取选中行的数据
selected_row = table.currentRow()
if selected_row >= 0:
name = table.item(selected_row, 0).text()
age = table.item(selected_row, 1).text()
print(f"选中:{name}, {age} 岁")
3.6 综合示例:一个简单的设置界面
好了,理论讲完了,咱们来点实战。下面这个例子,把今天学的所有控件组合起来,做一个简单的“用户设置”界面。
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QComboBox, QCheckBox, QRadioButton, QButtonGroup,
QListWidget, QTableWidget, QTableWidgetItem, QPushButton
)
class SettingsWidget(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
layout = QVBoxLayout()
# 1. 下拉框:选择语言
lang_layout = QHBoxLayout()
lang_layout.addWidget(QLabel("语言:"))
self.combo_lang = QComboBox()
self.combo_lang.addItems(["中文", "English", "日本語", "한국어"])
lang_layout.addWidget(self.combo_lang)
layout.addLayout(lang_layout)
# 2. 复选框:通知设置
self.cb_email = QCheckBox("邮件通知")
self.cb_sms = QCheckBox("短信通知")
self.cb_push = QCheckBox("推送通知")
layout.addWidget(self.cb_email)
layout.addWidget(self.cb_sms)
layout.addWidget(self.cb_push)
# 3. 单选框:主题选择
theme_layout = QHBoxLayout()
theme_layout.addWidget(QLabel("主题:"))
self.rb_light = QRadioButton("浅色")
self.rb_dark = QRadioButton("深色")
self.rb_auto = QRadioButton("自动")
theme_group = QButtonGroup()
theme_group.addButton(self.rb_light, 1)
theme_group.addButton(self.rb_dark, 2)
theme_group.addButton(self.rb_auto, 3)
self.rb_light.setChecked(True)
theme_layout.addWidget(self.rb_light)
theme_layout.addWidget(self.rb_dark)
theme_layout.addWidget(self.rb_auto)
layout.addLayout(theme_layout)
# 4. 列表:快捷操作
self.list_shortcuts = QListWidget()
self.list_shortcuts.addItems(["新建文件", "打开文件", "保存文件", "导出数据"])
layout.addWidget(QLabel("快捷操作:"))
layout.addWidget(self.list_shortcuts)
# 5. 表格:最近文件
self.table_recent = QTableWidget()
self.table_recent.setRowCount(3)
self.table_recent.setColumnCount(2)
self.table_recent.setHorizontalHeaderLabels(["文件名", "修改时间"])
recent_data = [
["report.docx", "2024-01-15"],
["data.xlsx", "2024-01-14"],
["presentation.pptx", "2024-01-13"]
]
for row, row_data in enumerate(recent_data):
for col, value in enumerate(row_data):
self.table_recent.setItem(row, col, QTableWidgetItem(value))
layout.addWidget(QLabel("最近文件:"))
layout.addWidget(self.table_recent)
# 保存按钮
btn_save = QPushButton("保存设置")
btn_save.clicked.connect(self.save_settings)
layout.addWidget(btn_save)
self.setLayout(layout)
def save_settings(self):
lang = self.combo_lang.currentText()
email_notify = self.cb_email.isChecked()
sms_notify = self.cb_sms.isChecked()
push_notify = self.cb_push.isChecked()
print(f"语言:{lang}")
print(f"通知:邮件={email_notify}, 短信={sms_notify}, 推送={push_notify}")
print("设置已保存!")
嗯,今天就到这里。代码不多,但每个控件都值得你亲手敲一遍。尤其是表格,多练练增删改查,后面做项目会非常顺手。