9

【Qt6】列表模型——树形列表 - 东邪独孤

 11 months ago
source link: https://www.cnblogs.com/tcjiaan/p/17736874.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

【Qt6】列表模型——树形列表

QStandardItemModel 类作为标准模型,主打“类型通用”,前一篇水文中,老周还没提到树形结构的列表,本篇咱们就好好探讨一下这货。

还是老办法,咱们先做示例,然后再聊知识点。下面这个例子,使用 QTreeView 组件来显示数据,使用的列表模型比较简单,只有一列。

#include <QApplication>
#include <QTreeView>
#include <QStandardItem>
#include <QStandardItemModel>

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);

    // 创建组件实例
    QTreeView *viewWind = new QTreeView(nullptr);
    // 创建数据模型
    QStandardItemModel* model;
    model = new QStandardItemModel(viewWind);
    // 顶级节点
    QStandardItem* top1 = new QStandardItem("工程部");
    // 添加子节点
    top1->setChild(0/*行号*/, new QStandardItem("螺母组"));
    top1->setChild(1, new QStandardItem("电钻组"));

    // 继续添加顶层节点
    QStandardItem *top2 = new QStandardItem("情报部");
    // 添加子节点
    top2->setChild(0, new QStandardItem("偷窥组"));
    top2->setChild(1, new QStandardItem("监听组"));

    // 把两个顶层节点添加到模型中
    model->setItem(0/*行号*/, top1);
    model->setItem(1, top2);
    // 将模型应用到视图
    viewWind->setModel(model);
    // 显示视图窗口
    viewWind->show();

    return QApplication::exec();
}

最先添加到 QStandarItemModel 的 QStandardItem 被视为树的顶层节点。调用顶层节点的 setChild 方法会添加子节点。从数据模型的角度看,子节点可以是一个二维表,即可以指定行号和列号的。不过,上面这个示例咱们只用了一列,即列号一直是0,所以调用的重载方法只需指定行号即可。其签名如下:

void setChild(int arow, QStandardItem *aitem)

arow 参数指定的是行的索引,要将子项放在第一行就传 0,放在第二行就传1,等等。此重载版本忽略了列号。

QStandardItem 对象之间建立好层次关系后,最终还要添加到 QStandardItemModel 中的,不然前面的工夫就白做了——数据当然要放进模型中的嘛。

当模型准备好后,调用视图组件的 setModel 方法呈现模型数据。

viewWind->setModel(model);

最终效果可以看下图:

367389-20230929122133629-1044708344.png

你可能会疑惑:左上角那个“1”是什么鬼?那个鬼是列号,咱们这例子只有一列,所以显示了默认列号。一般单列数据不需要列标题,可以将其隐藏。

viewWind->setHeaderHidden(true);

true 表示隐藏行、列标题,false 表示显示标题。

这样看起来就顺眼多了。

367389-20230929122735843-1090684572.png

Qt 的 TreeView 有一点很不错,就是可以显示多列。比如,下面这个例子,列表项包含三列。

#include <QApplication>
#include <QStandardItem>
#include <QStandardItemModel>
#include <QTreeView>

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);

    // 视图
    QTreeView* view = new QTreeView;
    // 模型
    QStandardItemModel *model = new QStandardItemModel;

    // 顶层节点1
    QStandardItem* root1 = new QStandardItem("普通班");
    // 添加子节点
    // 第一行
    QStandardItem* sub11 = new QStandardItem("230566");
    QStandardItem* sub12 = new QStandardItem("小齐");
    QStandardItem* sub13 = new QStandardItem("老齐");
    root1->setChild(0, 0, sub11);
    root1->setChild(0, 1, sub12);
    root1->setChild(0,2, sub13);
    // 第二行,可以直接插入QStandardItem实例
    root1->setChild(1, 0, new QStandardItem("230524"));
    root1->setChild(1, 1, new QStandardItem("小王"));
    root1->setChild(1, 2, new QStandardItem("隔壁老王"));
    // 添加到模型中
    model->setItem(0, root1);

    // 添加顶层节点2
    // 可以直接设置,不声明变量
    model->setItem(1, new QStandardItem("VIP班"));
    // 添加子项
    // 第一行
    model->item(1, 0)->setChild(0,0,new QStandardItem("2309291"));
    model->item(1, 0)->setChild(0,1,new QStandardItem("小曾"));
    model->item(1, 0)->setChild(0,2,new QStandardItem("老曾"));
    // 第二行
    model->item(1, 0)->setChild(1,0,new QStandardItem("2307266"));
    model->item(1, 0)->setChild(1, 1,new QStandardItem("小郑"));
    model->item(1, 0)->setChild(1,2,new QStandardItem("老郑"));

    // 顶层节点3
    model->setItem(2, new QStandardItem("神童班"));
    // 第一行
    model->item(2, 0)->setChild(0,0,new QStandardItem("23061685"));
    model->item(2, 0)->setChild(0,1, new QStandardItem("小季"));
    model->item(2, 0)->setChild(0, 2,new QStandardItem("扯牛堂认证医师老季"));
    // 第二行
    model->item(2, 0)->setChild(1,0,new QStandardItem("23064217"));
    model->item(2, 0)->setChild(1,1,new QStandardItem("小陆"));
    model->item(2, 0)->setChild(1,2,new QStandardItem("老陆"));
    // 第三行
    model->item(2, 0)->setChild(2,0, new QStandardItem("23031982"));
    model->item(2, 0)->setChild(2,1,new QStandardItem("小严"));
    model->item(2, 0)->setChild(2,2,new QStandardItem("严嵩第11代孙"));

    // 设置列标题
    model->setHorizontalHeaderLabels({"学号", "姓名", "家长代表"});
    // 把模型设置到视图
    view->setModel(model);
    view->setWindowTitle("厚黑幼儿园");
    // 显示视图
    view->show();

    return QApplication::exec();
}

虽然在列表模型中,每个 QStandardItem 都可以把整个二维表作为子节点,而且任意行、列处的项都可以拥有子节点。但是,QTreeView 视图只允许第一列出现折叠效果,所以,对于可折叠的父节点,咱们用一列就可以了,就算设置了多列也没有效果的。不妨想一下,如果每个单元格都可以折叠,那么不仅这控件设计起来困难,而看起来也很混乱,用户没法用了。所以,QTreeView 只认第一列可以折叠。

model 的 setHorizontalHeaderLabels 方法用来设置水平方向上的标题,参数是一个字符串列表。水平方向就是列标题;如果是行标题,就是垂直方向,要调用 setVerticalHeaderLabels 方法。不过,行标题一般不怎么用,顶多显示行号。

最终显示的效果如下:

367389-20230929133154236-1715775357.png

这个可以显示多列的 TreeView 真的很不错,可惜 .NET 中的 WinForms 和 WPF 自带控件 TreeView 没有这个玩法。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK