高级控件
Qt 提供了多种复杂的数据展示和编辑控件,本节介绍表格、树形、列表等高级控件的使用。
QListWidget(列表控件)
用于显示简单的列表数据,支持单选、多选和自定义项。
#include <QListWidget>
#include <QListWidgetItem>
// 创建列表控件
QListWidget *listWidget = new QListWidget(this);
// 添加项目
listWidget->addItem("项目 1");
listWidget->addItem("项目 2");
// 带图标的项目
QListWidgetItem *item = new QListWidgetItem(
QIcon(":/icons/file.png"),
"文档.txt"
);
listWidget->addItem(item);
// 一次性添加多个
QStringList items;
items << "苹果" << "香蕉" << "橙子" << "葡萄";
listWidget->addItems(items);
// 设置选择模式
listWidget->setSelectionMode(QAbstractItemView::SingleSelection); // 单选(默认)
// listWidget->setSelectionMode(QAbstractItemView::MultiSelection); // 多选
// listWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); // 扩展选择(Ctrl/Shift)
// 设置视图模式
listWidget->setViewMode(QListView::ListMode); // 列表模式(默认)
// listWidget->setViewMode(QListView::IconMode); // 图标模式
// 信号
connect(listWidget, &QListWidget::itemClicked, this, [=](QListWidgetItem *item) {
qDebug() << "点击:" << item->text();
});
connect(listWidget, &QListWidget::itemDoubleClicked, this, [=](QListWidgetItem *item) {
qDebug() << "双击:" << item->text();
});
connect(listWidget, &QListWidget::currentItemChanged, this,
[=](QListWidgetItem *current, QListWidgetItem *previous) {
if (current) {
qDebug() << "当前项变为:" << current->text();
}
});
// 获取选中项
QListWidgetItem *currentItem = listWidget->currentItem();
if (currentItem) {
QString text = currentItem->text();
}
// 获取所有选中项(多选模式)
QList<QListWidgetItem*> selectedItems = listWidget->selectedItems();
for (QListWidgetItem *item : selectedItems) {
qDebug() << "选中:" << item->text();
}
// 删除项目
delete listWidget->takeItem(row); // 删除指定行
delete listWidget->currentItem(); // 删除当前项
// 清空列表
listWidget->clear();
// 自定义项目数据
item->setData(Qt::UserRole, 123); // 存储自定义数据
int userData = item->data(Qt::UserRole).toInt();
QTableWidget(表格控件)
二维表格控件,适合展示结构化数据。
#include <QTableWidget>
#include <QTableWidgetItem>
// 创建表格(10行4列)
QTableWidget *tableWidget = new QTableWidget(10, 4, this);
// 设置表头
QStringList headers;
headers << "姓名" << "年龄" << "部门" << "工资";
tableWidget->setHorizontalHeaderLabels(headers);
// 设置单元格内容
tableWidget->setItem(0, 0, new QTableWidgetItem("张三"));
tableWidget->setItem(0, 1, new QTableWidgetItem("28"));
tableWidget->setItem(0, 2, new QTableWidgetItem("技术部"));
tableWidget->setItem(0, 3, new QTableWidgetItem("15000"));
// 批量填充数据
for (int row = 1; row < 10; row++) {
tableWidget->setItem(row, 0, new QTableWidgetItem(QString("员工%1").arg(row)));
tableWidget->setItem(row, 1, new QTableWidgetItem(QString::number(20 + row)));
tableWidget->setItem(row, 2, new QTableWidgetItem("销售部"));
tableWidget->setItem(row, 3, new QTableWidgetItem(QString::number(8000 + row * 500)));
}
// 调整列宽
tableWidget->setColumnWidth(0, 100);
tableWidget->setColumnWidth(1, 60);
tableWidget->setColumnWidth(2, 120);
tableWidget->setColumnWidth(3, 100);
// 或者让列自动调整
// tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
// tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
// 设置行高
tableWidget->setRowHeight(0, 30);
// 设置编辑模式
tableWidget->setEditTriggers(QAbstractItemView::DoubleClicked |
QAbstractItemView::EditKeyPressed);
// 选择行为
tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); // 整行选择
// QAbstractItemView::SelectItems - 单元格选择(默认)
// QAbstractItemView::SelectColumns - 整列选择
// 交替行颜色
tableWidget->setAlternatingRowColors(true);
// 网格线
tableWidget->setShowGrid(true);
tableWidget->setGridStyle(Qt::DotLine);
// 信号
connect(tableWidget, &QTableWidget::cellClicked, this,
[=](int row, int column) {
QTableWidgetItem *item = tableWidget->item(row, column);
if (item) {
qDebug() << "点击单元格:" << row << column << item->text();
}
});
connect(tableWidget, &QTableWidget::itemChanged, this,
[=](QTableWidgetItem *item) {
qDebug() << "单元格内容改变:" << item->text();
});
// 获取和修改数据
QTableWidgetItem *item = tableWidget->item(row, column);
if (item) {
QString text = item->text();
item->setText("新值");
item->setBackground(QBrush(Qt::yellow)); // 设置背景色
item->setForeground(QBrush(Qt::red)); // 设置文字颜色
item->setTextAlignment(Qt::AlignCenter); // 居中对齐
}
// 插入和删除行
tableWidget->insertRow(row); // 在指定位置插入行
tableWidget->removeRow(row); // 删除行
tableWidget->clearContents(); // 清空内容(保留表头)
// 排序
tableWidget->setSortingEnabled(true);
QTreeWidget(树形控件)
用于展示层次结构数据,如文件系统、组织架构等。
#include <QTreeWidget>
#include <QTreeWidgetItem>
// 创建树形控件
QTreeWidget *treeWidget = new QTreeWidget(this);
// 设置表头
treeWidget->setHeaderLabels(QStringList() << "名称" << "大小" << "修改日期");
// 添加顶层项目
QTreeWidgetItem *root1 = new QTreeWidgetItem(treeWidget);
root1->setText(0, "项目 A");
root1->setText(1, "-");
root1->setText(2, "2024-01-15");
root1->setIcon(0, QIcon(":/icons/folder.png"));
// 添加子项目
QTreeWidgetItem *child1 = new QTreeWidgetItem(root1);
child1->setText(0, "文档 1");
child1->setText(1, "15 KB");
child1->setText(2, "2024-01-10");
child1->setIcon(0, QIcon(":/icons/file.png"));
QTreeWidgetItem *child2 = new QTreeWidgetItem(root1);
child2->setText(0, "文档 2");
child2->setText(1, "23 KB");
child2->setText(2, "2024-01-12");
// 展开节点
root1->setExpanded(true);
// 另一种添加方式(更简洁)
QTreeWidgetItem *root2 = new QTreeWidgetItem(treeWidget,
QStringList() << "项目 B" << "-" << "2024-01-20");
new QTreeWidgetItem(root2, QStringList() << "子项 1" << "5 KB" << "2024-01-18");
new QTreeWidgetItem(root2, QStringList() << "子项 2" << "8 KB" << "2024-01-19");
// 设置列宽
treeWidget->setColumnWidth(0, 200);
treeWidget->setColumnWidth(1, 80);
treeWidget->setColumnWidth(2, 120);
// 信号
connect(treeWidget, &QTreeWidget::itemClicked, this,
[=](QTreeWidgetItem *item, int column) {
qDebug() << "点击:" << item->text(0) << "列:" << column;
});
connect(treeWidget, &QTreeWidget::itemDoubleClicked, this,
[=](QTreeWidgetItem *item, int column) {
// 双击编辑
item->setFlags(item->flags() | Qt::ItemIsEditable);
});
connect(treeWidget, &QTreeWidget::itemExpanded, this,
[=](QTreeWidgetItem *item) {
qDebug() << "展开:" << item->text(0);
});
connect(treeWidget, &QTreeWidget::itemCollapsed, this,
[=](QTreeWidgetItem *item) {
qDebug() << "折叠:" << item->text(0);
});
// 获取当前项
QTreeWidgetItem *currentItem = treeWidget->currentItem();
if (currentItem) {
QString name = currentItem->text(0);
// 获取父项
QTreeWidgetItem *parent = currentItem->parent();
// 获取子项数量
int childCount = currentItem->childCount();
// 获取特定子项
QTreeWidgetItem *child = currentItem->child(0);
}
// 递归遍历所有项
void traverseTree(QTreeWidgetItem *item, int level = 0)
{
if (!item) return;
QString indent(level * 2, ' ');
qDebug() << indent + item->text(0);
for (int i = 0; i < item->childCount(); i++) {
traverseTree(item->child(i), level + 1);
}
}
// 从根开始遍历
for (int i = 0; i < treeWidget->topLevelItemCount(); i++) {
traverseTree(treeWidget->topLevelItem(i));
}
// 删除项
delete treeWidget->currentItem(); // 删除当前项
// 清空
treeWidget->clear();
QComboBox(下拉框)进阶
#include <QComboBox>
QComboBox *comboBox = new QComboBox(this);
// 添加带数据的项
comboBox->addItem("北京", 110000);
comboBox->addItem("上海", 310000);
comboBox->addItem("广州", 440100);
comboBox->addItem("深圳", 440300);
// 获取当前选择的数据
int cityCode = comboBox->currentData().toInt();
QString cityName = comboBox->currentText();
// 查找并设置
int index = comboBox->findData(310000);
if (index >= 0) {
comboBox->setCurrentIndex(index);
}
// 可编辑下拉框
comboBox->setEditable(true);
comboBox->setInsertPolicy(QComboBox::InsertAtBottom);
// 自动补全
QCompleter *completer = comboBox->completer();
completer->setFilterMode(Qt::MatchContains); // 包含匹配
// 模型/视图模式(大数据量时使用)
QStandardItemModel *model = new QStandardItemModel(this);
for (int i = 0; i < 1000; i++) {
QStandardItem *item = new QStandardItem(QString("项 %1").arg(i));
model->appendRow(item);
}
comboBox->setModel(model);
QProgressBar(进度条)进阶
#include <QProgressBar>
QProgressBar *progressBar = new QProgressBar(this);
// 范围设置
progressBar->setRange(0, 100);
progressBar->setValue(50);
// 文本格式
progressBar->setFormat("%p% (%v/%m)"); // %p=百分比, %v=当前值, %m=最大值
progressBar->setAlignment(Qt::AlignCenter);
// 文本方向
progressBar->setOrientation(Qt::Horizontal); // 水平(默认)
// progressBar->setOrientation(Qt::Vertical); // 垂直
// 不确定模式(加载中动画)
progressBar->setRange(0, 0);
// 样式定制
progressBar->setStyleSheet(R"(
QProgressBar {
border: 2px solid grey;
border-radius: 5px;
text-align: center;
}
QProgressBar::chunk {
background-color: #4CAF50;
width: 10px;
margin: 0.5px;
}
)");
完整示例:文件浏览器
class FileBrowser : public QWidget
{
Q_OBJECT
public:
FileBrowser(QWidget *parent = nullptr) : QWidget(parent)
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
// 路径输入
QHBoxLayout *pathLayout = new QHBoxLayout();
QLineEdit *pathEdit = new QLineEdit(QDir::homePath());
QPushButton *browseBtn = new QPushButton("浏览");
pathLayout->addWidget(pathEdit);
pathLayout->addWidget(browseBtn);
mainLayout->addLayout(pathLayout);
// 分割器
QSplitter *splitter = new QSplitter(Qt::Horizontal);
// 左侧树形目录
treeWidget = new QTreeWidget();
treeWidget->setHeaderLabel("目录");
loadDirectory(QDir::homePath(), treeWidget->invisibleRootItem());
splitter->addWidget(treeWidget);
// 右侧文件列表
listWidget = new QListWidget();
splitter->addWidget(listWidget);
mainLayout->addWidget(splitter);
// 状态栏
QLabel *statusLabel = new QLabel("就绪");
mainLayout->addWidget(statusLabel);
// 信号连接
connect(treeWidget, &QTreeWidget::itemClicked, this,
[=](QTreeWidgetItem *item, int) {
QString path = item->data(0, Qt::UserRole).toString();
loadFiles(path);
statusLabel->setText(QString("当前目录: %1").arg(path));
});
connect(listWidget, &QListWidget::itemDoubleClicked, this,
[=](QListWidgetItem *item) {
QString filePath = item->data(Qt::UserRole).toString();
QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));
});
connect(browseBtn, &QPushButton::clicked, this, [=]() {
QString dir = QFileDialog::getExistingDirectory(this, "选择目录");
if (!dir.isEmpty()) {
pathEdit->setText(dir);
treeWidget->clear();
loadDirectory(dir, treeWidget->invisibleRootItem());
}
});
splitter->setSizes(QList<int>() << 300 << 500);
}
private:
void loadDirectory(const QString &path, QTreeWidgetItem *parent)
{
QDir dir(path);
QFileInfoList entries = dir.entryInfoList(
QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &info : entries) {
QTreeWidgetItem *item = new QTreeWidgetItem(parent);
item->setText(0, info.fileName());
item->setIcon(0, style()->standardIcon(QStyle::SP_DirIcon));
item->setData(0, Qt::UserRole, info.absoluteFilePath());
// 递归加载子目录(可优化为懒加载)
// loadDirectory(info.absoluteFilePath(), item);
}
}
void loadFiles(const QString &path)
{
listWidget->clear();
QDir dir(path);
QFileInfoList entries = dir.entryInfoList(
QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &info : entries) {
QListWidgetItem *item = new QListWidgetItem();
item->setText(info.fileName());
item->setData(Qt::UserRole, info.absoluteFilePath());
if (info.isDir()) {
item->setIcon(style()->standardIcon(QStyle::SP_DirIcon));
} else {
item->setIcon(style()->standardIcon(QStyle::SP_FileIcon));
}
listWidget->addItem(item);
}
}
QTreeWidget *treeWidget;
QListWidget *listWidget;
};
下一步
继续学习 对话框,掌握消息框、文件对话框等常用对话框的使用。