TreeView是在Qt6.3中加入的,弥补了Qt中无官方树图。笔者上手尝试了下,虽然有点麻烦,但官方也做了不少简化。
本次教程,笔者创建一个简单的示例,以帮助读者使用TreeView。
当前模型需要使用C++定义,模型类继承自QAbstractItemModel,笔者的头文件如下
- class TreeItem;
-
- class TreeModel : public QAbstractItemModel
- {
- Q_OBJECT
-
- public:
- enum TreeRole {
- FullNameRole = Qt::DisplayRole,
- AddressRole = Qt::UserRole
- };
- Q_ENUM(TreeRole)
- explicit TreeModel(QObject *parent = nullptr);
- ~TreeModel();
-
- // Header:
- QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
-
- // bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override;
-
- // Basic functionality:
- QModelIndex index(int row, int column,
- const QModelIndex &parent = QModelIndex()) const override;
- QModelIndex parent(const QModelIndex &index) const override;
-
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- int columnCount(const QModelIndex &parent = QModelIndex()) const override;
-
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
- QHash<int, QByteArray> roleNames() const override;
-
- // Editable:
- bool setData(const QModelIndex &index, const QVariant &value,
- int role = Qt::EditRole) override;
-
- Qt::ItemFlags flags(const QModelIndex& index) const override;
-
-
- private:
-
- void setupModelData(TreeItem *parent);
- TreeItem *getItem(const QModelIndex &index) const;
-
- TreeItem *rootItem;
- };
与TableView的模型相关,多了index()和parent()的实现
模型类实现后,可以注册到qml中
qmlRegisterType("TreeModelTest", 1, 0, "TreeModel");
- TreeView {
- id: treeView
- //模型
- model: TreeModel {}
- //委托
- delegate: TreeViewDelegate {}
- //边界操作
- boundsBehavior: Flickable.StopAtBounds
- //水平滚动条
- ScrollBar.horizontal: ScrollBar {}
- //垂直滚动条
- ScrollBar.vertical: ScrollBar {}
- }
树形视图的实现比较好理解,可以调整很多属性
TreeViewDelegate是Qt内置的委托,也可以自定义实现
注:
TreeView继承自TableView,所以TableView可以使用的东西,TreeView也可以使用。
- HorizontalHeaderView {
- id: tableView_topHeader
- anchors.left: treeView.left
- anchors.right: treeView.right
- anchors.top: parent.top
- syncView: treeView
- }
若不指定水平表头的模型数据,默认会调用模型的headerData()函数获取,需要在C++中实现。
syncView属性可以将treeView的水平位置或列宽等信息,同步到水平表头,这样就不要再单独调用相关属性了。
注:
HorizontalHeaderView继承自TableView,所以TableView可以使用的东西,HorizontalHeaderView也可以使用。
- VerticalHeaderView {
- id: tableView_leftHeader
- anchors.left: parent.left
- anchors.top: treeView.top
- anchors.bottom: treeView.bottom
- syncView: treeView
- model: treeView.rows
- }
若不指定水平表头的模型数据,默认会调用模型的headerData()函数获取,但要注意,headerData()只能返回最顶层的表头数据,导致显示异常。笔者建议直接绑定TreeView的行数或自定义。
syncView属性可以将treeView的垂直位置或列高等信息,同步到垂直表头,这样就不要再单独调用相关属性了。
注:
VerticalHeaderView继承自TableView,所以TableView可以使用的东西,VerticalHeaderView也可以使用。
- TreeView {
- id: treeView
- //模型
- model: TreeModel {}
- //选择模型
- selectionModel: ItemSelectionModel{ id: itemSelectionModel}
- //委托
- delegate: TreeViewDelegate {}
- //边界操作
- boundsBehavior: Flickable.StopAtBounds
- //水平滚动条
- ScrollBar.horizontal: ScrollBar {}
- //垂直滚动条
- ScrollBar.vertical: ScrollBar {}
- }
笔者测试了下Qt自带的选择模型,win10下效果还不错,但在android下的效果欠佳

- treeView.delegate: TreeViewDelegate {
- TapHandler {
- acceptedButtons: Qt.RightButton
- onTapped: {
- console.debug("currentIndex",row,column,index,
- treeView.modelIndex(column, row),
- model.display )
- }
- }
-
- }
TreeView读取模型数据,和一般视图相同,但也有一些区别。和其他视图-模型不同,TreeView的row、column是视图中的显示的行与列(从0开始),index是视图中的列向叠加序列(自上而下,先计算第0列,再依次叠加后面几列)。模型中的行是相对于父对象的。也就是说,视图的row、column、index与模型中的不同,但存在对应关系。可以TreeView里的函数获取,如 columnAtIndex()、 modelIndex()、 rowAtIndex()等。
笔者使用的测试源码
TreeView可以自定义表头,以实现复杂的表头设计。
时间所限,笔者只是显示了TreeView的简单用法,且仅在win10和android下简单测试。其中定有不足,请小伙伴指正。