1 简述
- 在实际开发中可能会用到类似树型控件的需求,在Qt中
QTreeWidget
是一个方便的类,它提供了一个标准的树形小部件,带有一个经典的基于项目的接口。这个类基于Qt的模型/视图架构,并使用一个默认模型来保存项目,每个项目都是一个QTreeWidgetItem。- 本节模仿WPS导航窗格中书签的界面,用QTreeWidget实现其大概的界面。
开发环境
- 系统:Window10
- Qt版本:5.14.2
- 编译器:MinGW_64
2 实现效果
3 实现步骤
- 初始化QTreeWidget数据
ui->treeWidget->setHeaderHidden(true);
ui->treeWidget->setColumnCount(1);
ui->treeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
ui->treeWidget->setDragEnabled(true);
ui->treeWidget->setDragDropMode(QAbstractItemView::InternalMove);
ui->treeWidget->setEditTriggers(QAbstractItemView::DoubleClicked);
ui->treeWidget->viewport()->setAcceptDrops(true);
ui->treeWidget->setDropIndicatorShown(true);
ui->treeWidget->setFocusPolicy(Qt::NoFocus);
QFile file(":/res/style.qss");
if (file.open(QFile::ReadOnly)) {
QString qss = file.readAll();
this->setStyleSheet(qss);
file.close();
}
- 读取文件数据并将每行数据添加到QTreeWidget
void Widget::initTreeData()
{
QFile file(":/res/bookmark.txt");
if (!file.open(QFile::ReadOnly)) {
qInfo() << "文件打开失败!";
return;
}
QString line;
QStringList rowList;
while (!file.atEnd()) {
line = file.readLine();
rowList.append(line);
}
initContentsOfTreeRow(rowList);
file.close();
// 记录前一个项
previousParentNode = nullptr;
}
// 处理每行数据
void Widget::initContentsOfTreeRow(const QStringList &rowListContent)
{
int rowCount = rowListContent.size();
for (int i = 0; i < rowCount; ++i) {
QString rowContent = rowListContent.at(i).trimmed();
if (rowContent.startsWith("--")) { // 是子结点
QTreeWidgetItem *childItem = new QTreeWidgetItem(previousParentNode);
childItem->setIcon(0, QIcon(":/res/bookmark.png"));
childItem->setText(0, rowContent.mid(2));
childItem->setSizeHint(0, QSize(childItem->sizeHint(0).width(), 35));
childItem->setFlags(childItem->flags() | Qt::ItemIsEditable);
} else { // 顶层结点
QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeWidget);
item->setIcon(0, QIcon(":/res/bookmark.png"));
item->setText(0, rowContent);
item->setSizeHint(0, QSize(item->sizeHint(0).width(), 35));
item->setFlags(item->flags() | Qt::ItemIsEditable);
previousParentNode = item;
}
}
}
- bookmark.txt数据
致谢|5
介绍|6
前言|9
关于本书|11
关于作者|13
关于封面|14
第1章 你好,C++的并发世界|15
--1.1 何谓并发|16
--1.2 为什么使用并发?|20
--1.3 C++中的并发和多线程|22
--1.4 开始入门|24
--1.5 本章总结|26
第2章 线程管理|27
--2.1 线程管理的基础|28
--2.2 向线程函数传递参数|34
--2.3 转移线程所有权|37
--2.4 运行时决定线程数量|41
--2.5 标识线程|44
--2.6 本章总结|45
第3章 线程间共享数据|46
--3.1 共享数据带来的问题|47
--3.2 使用互斥量保护共享数据|50
- 添加项和删除项
// ----------添加项----------
QTreeWidgetItem * curItem = nullptr;
if (ui->treeWidget->topLevelItemCount() != 0) { // 有顶层项
curItem = ui->treeWidget->currentItem(); // 获取当前项
}
if (curItem != nullptr) {
QTreeWidgetItem *parentItem = curItem->parent();
QTreeWidgetItem *item = nullptr;
if (parentItem == nullptr) { // 没有父节点
item = new QTreeWidgetItem();
item->setIcon(0, QIcon(":/res/bookmark.png"));
item->setText(0, "【书签】新建书签");
item->setSizeHint(0, QSize(item->sizeHint(0).width(), 35));
item->setFlags(item->flags() | Qt::ItemIsEditable);
int index = ui->treeWidget->indexOfTopLevelItem(curItem); // 在顶层列表中的索引
ui->treeWidget->insertTopLevelItem(index + 1, item);
} else { // 有父节点
item = new QTreeWidgetItem();
item->setIcon(0, QIcon(":/res/bookmark.png"));
item->setText(0, "【书签】新建书签");
item->setSizeHint(0, QSize(item->sizeHint(0).width(), 35));
item->setFlags(item->flags() | Qt::ItemIsEditable);
int index = parentItem->indexOfChild(curItem); // 子元素列表中子元素的索引
parentItem->insertChild(index + 1, item);
}
// 添加完后需将此项设置为当前项
ui->treeWidget->setCurrentItem(item);
ui->treeWidget->editItem(item);
} else { // 当前没有项
QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeWidget);
item->setIcon(0, QIcon(":/res/bookmark.png"));
item->setText(0, "【书签】新建书签");
item->setSizeHint(0, QSize(item->sizeHint(0).width(), 35));
item->setFlags(item->flags() | Qt::ItemIsEditable);
}
//*****************************************************************************
// ----------添删除项----------
QTreeWidgetItem * curItem = nullptr;
if (ui->treeWidget->topLevelItemCount() != 0) { // 有顶层项
curItem = ui->treeWidget->currentItem();
}
if (curItem != nullptr) {
if (curItem->childCount() > 0) { // 有子项
QMessageBox::StandardButton btn = QMessageBox::information(this, "提示", "删除该书签将会删除其子书签,是否确定删除?",
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Ok);
if (btn == QMessageBox::Cancel) {
return;
}
}
QTreeWidgetItem *parentItem = curItem->parent();
if (parentItem == nullptr) { // 无父项
int index = ui->treeWidget->indexOfTopLevelItem(curItem);
delete ui->treeWidget->takeTopLevelItem(index);
} else { // 有父项
parentItem->removeChild(curItem);
delete curItem;
}
} else { // 当前没有项
QMessageBox::information(this, "提示", "当前无书签!");
}
4 总结
- 显示层级数据方便
- 可以添加复选框
- 支持自定义列表项:可根据自己的需求来
- 易于使用