【QT常用技术讲解】QTreeWidget实现树形筛选框(包含源码)
前言
QTableWidget显示的内容很多的时候,会有需要过滤显示的需求,比如资产列表、部门列表、目录列表等,树形筛选框很适合展示此类有上下级关系的数据。
效果图
本工具源码可在多个平台上编译。
功能讲解
本篇的案例包含的功能有:
- 根据目录绝对路径,构建全部目录节点;
- 树形筛选器的目录节点支持勾选;
- 树形筛选器支持横向和竖向滚动条;
- 获取勾选信息。
构建QTreeWidget树
关键点:QTreeWidget是带表头的(需要隐藏),并且有多列(只需要1列),默认支持竖向滚动,横向滚动需要设置。
void treefilterwidget::setupUI()
{ui->dirtreeWidget->setHeaderHidden(true);// 隐藏树形控件的表头(不显示列标题)ui->dirtreeWidget->setColumnCount(1);// 设置树形控件只有1列(单列布局)ui->dirtreeWidget->setAnimated(true);// 启用树节点的展开/折叠动画效果ui->dirtreeWidget->setIndentation(20);// 设置子节点缩进距离为20像素ui->dirtreeWidget->header()->setStretchLastSection(true);// 让最后一列自动拉伸填充剩余空间ui->dirtreeWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); // 按需显示水平滚动条ui->dirtreeWidget->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); // 像素级滚动ui->dirtreeWidget->header()->setSectionResizeMode(QHeaderView::ResizeToContents);// 列宽自适应内容ui->dirtreeWidget->header()->setStretchLastSection(false); // 禁止最后一列拉伸// 设置样式ui->dirtreeWidget->setStyleSheet(R"(QTreeWidget {background-color: white;border: 1px solid #cccccc;border-radius: 4px;font-family: Arial, sans-serif;}QTreeWidget::item {height: 28px;color: #333333;}QTreeWidget::item:selected {background-color: #e6f3ff;color: #0066cc;})");//ui->dirtreeWidget->expandAll();//所有节点展开
}
向树添加节点
关键点:QTreeWidget创建节点时,可设置名称、选项框(默认带有)、节点可勾选。
void treefilterwidget::addPath(const QString &path, Qt::CheckState state)
{if (path.isEmpty()) return;// 分割路径QStringList parts = path.split('/', QString::SkipEmptyParts);if (parts.isEmpty()) return;QTreeWidgetItem *currentParent = ui->dirtreeWidget->invisibleRootItem();// 逐级创建或查找节点for (int i = 0; i < parts.size(); ++i) {QString nodeName = parts[i];QTreeWidgetItem *existingItem = nullptr;// 检查是否已存在同名节点for (int j = 0; j < currentParent->childCount(); ++j) {if (currentParent->child(j)->text(0) == nodeName) {existingItem = currentParent->child(j);break;}}// 如果节点不存在,则创建if (!existingItem) {existingItem = new QTreeWidgetItem(currentParent);existingItem->setText(0, nodeName);//设置节点标题existingItem->setCheckState(0, (i == parts.size() - 1) ? state : Qt::Unchecked);//设置勾选框existingItem->setFlags(existingItem->flags() | Qt::ItemIsUserCheckable);//节点可勾选(显示复选框)}currentParent = existingItem;}
}
获取勾选信息
包含有3类勾选信息:
- 所有选中的节点
- 所有选中的叶子节点
- 所有部分选中的节点
// 获取所有部分选中的节点路径
QSet<QString> treefilterwidget::getPartiallySelectedPaths() const
{QSet<QString> result;// 遍历所有项目QTreeWidgetItemIterator it(ui->dirtreeWidget);while (*it) {if ((*it)->checkState(0) == Qt::PartiallyChecked) {QString path;QTreeWidgetItem *current = *it;// 构建路径while (current) {if (current->parent()) {path = "/" + current->text(0) + path;} else {path = current->text(0) + path;}current = current->parent();}result.insert(path);}++it;}return result;
}void treefilterwidget::collectSelectedPaths(QTreeWidgetItem *item, const QString ¤tPath, QSet<QString> &result, bool leavesOnly) const
{QString newPath = currentPath.isEmpty() ? item->text(0) : currentPath + "/" + item->text(0);// 如果只需要叶子节点,且当前节点不是叶子节点,则不添加if (!leavesOnly || item->childCount() == 0) {if (item->checkState(0) == Qt::Checked) {result.insert(newPath);}}// 递归处理子节点for (int i = 0; i < item->childCount(); ++i) {collectSelectedPaths(item->child(i), newPath, result, leavesOnly);}
}
篇尾
使用QTreeWidget的场景,通常会结合QTableWidget来展示筛选的信息,整体的风格与管理类工具的web端很相似,很容易让用户接受。