单位网站开发费用进什么科目/全自动推广引流软件免费
1. QTreeView 基础介绍
QTreeView 是 Qt 框架中用于显示树形结构数据的控件,属于模型/视图架构的一部分。它非常适合展示层次化数据,如文件系统、组织结构等。
主要特点:
-
支持多级层次结构显示
-
可展开/折叠节点
-
支持自定义节点样式
-
提供选择、编辑功能
-
可与 QFileSystemModel 等现成模型配合使用
2. 基本使用
2.1 简单示例
#include <QApplication>
#include <QTreeView>
#include <QStandardItemModel>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建模型QStandardItemModel model;// 添加数据QStandardItem *rootItem = model.invisibleRootItem();// 第一级节点QStandardItem *item1 = new QStandardItem("一级节点1");QStandardItem *item2 = new QStandardItem("一级节点2");rootItem->appendRow(item1);rootItem->appendRow(item2);// 第二级节点QStandardItem *item11 = new QStandardItem("二级节点1-1");QStandardItem *item12 = new QStandardItem("二级节点1-2");item1->appendRow(item11);item1->appendRow(item12);QStandardItem *item21 = new QStandardItem("二级节点2-1");item2->appendRow(item21);// 创建TreeViewQTreeView treeView;treeView.setModel(&model);treeView.setWindowTitle("树形视图示例");treeView.expandAll(); // 展开所有节点treeView.resize(400, 300);treeView.show();return app.exec();
}
2.2 常用方法
// 设置选择模式
treeView.setSelectionMode(QAbstractItemView::SingleSelection); // 单选
treeView.setSelectionMode(QAbstractItemView::MultiSelection); // 多选// 设置选择行为
treeView.setSelectionBehavior(QAbstractItemView::SelectRows); // 整行选择// 设置是否可编辑
treeView.setEditTriggers(QAbstractItemView::NoEditTriggers); // 不可编辑
treeView.setEditTriggers(QAbstractItemView::DoubleClicked); // 双击编辑// 设置展开/折叠动画
treeView.setAnimated(true);// 设置根节点是否显示
treeView.setRootIsDecorated(true); // 显示根节点装饰// 设置列数
treeView.setHeaderHidden(true); // 隐藏表头
3. 数据模型使用
3.1 使用 QStandardItemModel
QStandardItemModel *model = new QStandardItemModel(this);// 设置表头(多列情况)
model->setHorizontalHeaderLabels({"名称", "类型", "大小"});// 创建节点
QStandardItem *rootNode = model->invisibleRootItem();// 添加一级节点
QStandardItem *folderItem = new QStandardItem(QIcon(":/icons/folder.png"), "文件夹");
QStandardItem *typeItem = new QStandardItem("文件夹");
QStandardItem *sizeItem = new QStandardItem("-");
rootNode->appendRow({folderItem, typeItem, sizeItem});// 添加子节点
QStandardItem *fileItem = new QStandardItem(QIcon(":/icons/file.png"), "文档.txt");
QStandardItem *fileType = new QStandardItem("文本文件");
QStandardItem *fileSize = new QStandardItem("12 KB");
folderItem->appendRow({fileItem, fileType, fileSize});ui->treeView->setModel(model);
ui->treeView->setColumnWidth(0, 200); // 设置第一列宽度
3.2 使用 QFileSystemModel
QFileSystemModel *fileModel = new QFileSystemModel(this);
fileModel->setRootPath(QDir::homePath()); // 设置根路径// 设置过滤器
fileModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
fileModel->setNameFilters({"*.txt", "*.pdf"});
fileModel->setNameFilterDisables(false);ui->treeView->setModel(fileModel);
ui->treeView->setRootIndex(fileModel->index(QDir::homePath()));
ui->treeView->hideColumn(1); // 隐藏不需要的列
ui->treeView->hideColumn(2);
ui->treeView->hideColumn(3);
4. 自定义模型
继承 QAbstractItemModel 创建自定义树模型:
class TreeModel : public QAbstractItemModel {Q_OBJECTpublic:explicit TreeModel(QObject *parent = nullptr);// 必须实现的方法QModelIndex index(int row, int column, const QModelIndex &parent) const override;QModelIndex parent(const QModelIndex &child) const override;int rowCount(const QModelIndex &parent) const override;int columnCount(const QModelIndex &parent) const override;QVariant data(const QModelIndex &index, int role) const override;// 可选实现的方法QVariant headerData(int section, Qt::Orientation orientation, int role) const override;Qt::ItemFlags flags(const QModelIndex &index) const override;bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;private:struct TreeNode {QString name;QVector<TreeNode*> children;TreeNode *parent = nullptr;};TreeNode *rootNode;
};
4.1 关键方法实现
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const {if (!hasIndex(row, column, parent))return QModelIndex();TreeNode *parentNode = parent.isValid() ? static_cast<TreeNode*>(parent.internalPointer()) : rootNode;TreeNode *childNode = parentNode->children.value(row, nullptr);return childNode ? createIndex(row, column, childNode) : QModelIndex();
}QModelIndex TreeModel::parent(const QModelIndex &child) const {if (!child.isValid())return QModelIndex();TreeNode *childNode = static_cast<TreeNode*>(child.internalPointer());TreeNode *parentNode = childNode->parent;if (parentNode == rootNode)return QModelIndex();// 查找父节点在其父级的行号TreeNode *grandParentNode = parentNode->parent;int row = grandParentNode->children.indexOf(parentNode);return createIndex(row, 0, parentNode);
}int TreeModel::rowCount(const QModelIndex &parent) const {if (parent.column() > 0)return 0;TreeNode *parentNode = parent.isValid() ? static_cast<TreeNode*>(parent.internalPointer()) : rootNode;return parentNode->children.size();
}QVariant TreeModel::data(const QModelIndex &index, int role) const {if (!index.isValid())return QVariant();TreeNode *node = static_cast<TreeNode*>(index.internalPointer());switch (role) {case Qt::DisplayRole:return node->name;case Qt::DecorationRole:return QIcon(":/icons/node.png");case Qt::ToolTipRole:return QString("节点: %1").arg(node->name);default:return QVariant();}
}
5. 高级功能实现
5.1 自定义委托
class TreeItemDelegate : public QStyledItemDelegate {
public:using QStyledItemDelegate::QStyledItemDelegate;void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override {QStyleOptionViewItem opt = option;initStyleOption(&opt, index);// 自定义绘制painter->save();// 设置背景if (opt.state & QStyle::State_Selected) {painter->fillRect(opt.rect, QColor("#4CAF50"));} else if (opt.state & QStyle::State_MouseOver) {painter->fillRect(opt.rect, QColor("#E8F5E9"));} else {painter->fillRect(opt.rect, Qt::white);}// 绘制图标QRect iconRect = opt.rect.adjusted(2, 2, -opt.rect.width() + 30, -2);QIcon icon = index.data(Qt::DecorationRole).value<QIcon>();icon.paint(painter, iconRect);// 绘制文本QRect textRect = opt.rect.adjusted(32, 0, -10, 0);painter->setPen(opt.state & QStyle::State_Selected ? Qt::white : Qt::black);painter->drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft, opt.text);painter->restore();}QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override {return QSize(200, 30); // 固定行高}
};// 使用自定义委托
ui->treeView->setItemDelegate(new TreeItemDelegate(this));
5.2 拖放功能
// 启用拖放
ui->treeView->setDragEnabled(true);
ui->treeView->setAcceptDrops(true);
ui->treeView->setDropIndicatorShown(true);
ui->treeView->setDragDropMode(QAbstractItemView::InternalMove);// 在模型中实现拖放支持
Qt::DropActions TreeModel::supportedDropActions() const {return Qt::CopyAction | Qt::MoveAction;
}QStringList TreeModel::mimeTypes() const {return {"application/vnd.tree.item"};
}QMimeData *TreeModel::mimeData(const QModelIndexList &indexes) const {auto *mimeData = new QMimeData;QByteArray encodedData;QDataStream stream(&encodedData, QIODevice::WriteOnly);for (const QModelIndex &index : indexes) {if (index.isValid()) {TreeNode *node = static_cast<TreeNode*>(index.internalPointer());stream << node->name;}}mimeData->setData("application/vnd.tree.item", encodedData);return mimeData;
}bool TreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action,int row, int column, const QModelIndex &parent) {if (!data->hasFormat("application/vnd.tree.item"))return false;QByteArray encodedData = data->data("application/vnd.tree.item");QDataStream stream(&encodedData, QIODevice::ReadOnly);QStringList newItems;while (!stream.atEnd()) {QString text;stream >> text;newItems << text;}TreeNode *parentNode = parent.isValid() ? static_cast<TreeNode*>(parent.internalPointer()) : rootNode;beginInsertRows(parent, row, row + newItems.size() - 1);for (const QString &text : qAsConst(newItems)) {TreeNode *newNode = new TreeNode{text, {}, parentNode};parentNode->children.insert(row++, newNode);}endInsertRows();return true;
}
6. 信号与槽
// 当前项变化信号
connect(ui->treeView, &QTreeView::clicked, [](const QModelIndex &index){qDebug() << "点击了:" << index.data().toString();
});// 双击项目信号
connect(ui->treeView, &QTreeView::doubleClicked, [](const QModelIndex &index){qDebug() << "双击了:" << index.data().toString();
});// 展开/折叠信号
connect(ui->treeView, &QTreeView::expanded, [](const QModelIndex &index){qDebug() << "展开了:" << index.data().toString();
});connect(ui->treeView, &QTreeView::collapsed, [](const QModelIndex &index){qDebug() << "折叠了:" << index.data().toString();
});// 选择变化信号
connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [](const QItemSelection &selected, const QItemSelection &deselected){qDebug() << "选择已改变";});
7. 性能优化
-
懒加载子节点:只在展开时加载子节点数据
-
实现 fetchMore/canFetchMore:对于大数据集
-
使用 uniformRowHeights:如果行高固定可提高性能
-
避免在 data() 中进行复杂计算:预先计算好数据
-
批量更新:使用 beginResetModel/endResetModel 进行大批量更新