Qt QTreeView 常用属性及操作方法

1. QTreeView简介

TreeView、TableView、ListView是几个最常用的视图控件,其中TreeView具有分级功能完全可替代后两者使用。三者使用时都遵循View<->Model架构,TreeView本身只负责显示,对数据操作针对Model进行,模型数据的改变自动在视图中得以体现。

2. 常用属性

2.1. 单选、多选

// QAbstractItemView::SingleSelection 单选
// QAbstractItemView::MultiSelection  允许多选
// QAbstractItemView::NoSelection     不允许选择
treeView->setSelectionMode(QAbstractItemView::SingleSelection);

2.2. 整行、整列选取

// QAbstractItemView::SelectItems   单元格Item选择
// QAbstractItemView::SelectRows    整行选择
// QAbstractItemView::SelectColumns 整列选择
treeView->setSelectionBehavior(QAbstractItemView::SelectRows);

2.3. 焦点策略

// Qt::TabFocus      0x1
// Qt::ClickFocus    0x2
// Qt::StrongFocus   0xb (TabFoucs|ClickFocus|0x8)
// Qt::WheelFocus    0xf (StrongFoucs | 0x4)
// Qt::NoFocus       无焦点虚线框
treeView->setFocusPolicy(Qt::NoFocus);

2.4. 根节点展开控制

用来控制是否显示根节点前的展开控制,若设置为false,则根节点无法展开(即使添加了子节点,也无法看到)。如此一来,TreeView可替代作为ListView来使用。

// 显示根节点前的控制(默认)
treeView->setRootIsDecorated(true);

2.5. 交替颜色控制

交替颜色使能时,可通过样式表控制交替行的颜色。

treeView->setAlternatingRowColors(true);
treeView->setStyleSheet("QTreeView::item:alternate {background: #90a0d0;}
// QSS
QTreeView::item:alternate {background: #90a0d0;}

2.6. 显示、隐藏行或列

// 隐藏第一列
treeView->setColumnHidden(0, true);

// 隐藏第二行
treeView->setRowHidden(1, true);

2.7. 文字折叠

// 表格边界处按字换行显示,默认为false;
// 注意:这个属性是否起作用依赖于Qt::TextElideMode,
//   Qt::ElideLeft
//   Qt::ElideRight
//   Qt::ElideMiddle
//   Qt::ElideNone (不显示省略号)
treeView->setWordWrap(true);
treeView->setTextElideMode(Qt::ElideNone);

2.8. 排序

// 开启列排序
treeView->setSortingEnabled(true);
// 显示标题栏排序指示符
treeView->header()->setSortIndicatorShown(true);

// 第二列升序排序
treeView->sortByColumn(1, Qt::AscendingOrder);

2.9. 缩进

本属性设定每级Item以像素为单位的缩进大小,对于顶层Item,缩进表示从TreeView视口(viewPort)左边缘到首列的距离。

// 全部缩进
treeView->setIndentation(0);

2.10. 表格编辑方式

// 表格不可编辑
treeView->setEditTriggers(QAbstractItemView::NoEditTriggers);

2.11. 滚动条显示

// 单列TreeView显示横向滚动条
treeView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
treeView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);

3. 标题栏控制

3.1. 文字对齐

3.2. 标题栏显示、隐藏

// 隐藏表头
treeView->setHeaderHidden(false);
// 或
treeView->header()->hide();
treeView->header()->setHidden(true);

// 针对section单独控制,隐藏第二列标题
treeView->header()->setSectionHidden(1, true);

3.3. 标题栏高亮

treeView->header()->setHighlightSections(true);

3.4. 标题栏单元格对齐

// 顶部标题栏水平、垂直都居中对齐
treeView->header()->setDefaultAlignment(Qt::AlignCenter);

3.5. 标题栏尺寸设置

// 第一列固定列宽
treeView->header()->setSectionResizeMode(0, QHeaderView::Fixed);
treeView->setColumnWidth(0, 100);

// 第二列随内容尺寸自适应
treeView->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);

// 最右侧一列自动随TreeView窗口尺寸扩展
treeView->header()->setSectionResizeMode(treeView->header()->count - 1, QHeaderView::Stretch);

3.6. 标题栏样式

// 颜色渐变标题栏,变化方向:(x1,y1) -> (x2,y2)
// 鼠标飘过、表头按下颜色背景设置
treeView->header()->setStyleSheet(
    "QHeaderView::section {background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #3030B0, stop:1 #a0a0f0);"
    "color: white; padding-left: 4px; border: 1px solid #6c6c6c;}"
    "QHeaderView::section:horizontal:hover {color: white; background: #905090;}"
    "QHeaderView::section:horizontal:pressed {color: white; background: #505090;}");

4. 示例

4.1. 建树

void MainWindow::initTreeView(QTreeView *treeView)
{
    // 若数据模型已存在则清空,在本函数内重新分配
    if (m_treeModel)
    {
        m_treeModel->clear();
        delete m_treeModel;
        m_treeModel = nullptr;
    }

    // 创建数据模型并绑定到treeView
    m_treeModel = new QStandardItemModel(this);
    treeView->setModel(m_treeModel);

    // 创建标题栏,共四列,文字居中对齐
    m_treeModel->setColumnCount(4);
    QStringList headerItems;
    headerItems << QString("姓名") << QString("语文") << QString("数学") << QString("英语");
    m_treeModel->setHorizontalHeaderLabels(headerItems);
    treeView->header()->setDefaultAlignment(Qt::AlignCenter);

    // 第一列固定列宽
    treeView->header()->setSectionResizeMode(0, QHeaderView::Fixed);
    treeView->setColumnWidth(0, 150);
    // 最后一列自动拉伸
    treeView->header()->setSectionResizeMode(treeView->header()->count() - 1, QHeaderView::Stretch);

    // 高亮标题栏文字(加粗)
    treeView->header()->setHighlightSections(true);

    // 单选
    treeView->setSelectionMode(QAbstractItemView::SingleSelection);
    // 整行选择
    treeView->setSelectionBehavior(QAbstractItemView::SelectRows);
    // 焦点策略:无焦点虚线框
    treeView->setFocusPolicy(Qt::NoFocus);
    // 交替颜色
    treeView->setAlternatingRowColors(true);

    // 开启列排序
    treeView->setSortingEnabled(true);
    // 显示标题栏排序箭头
    treeView->header()->setSortIndicatorShown(true);

    // 根节点是否可见,如果为false,根节点将不能展开,TreeView成为ListView
    treeView->setRootIsDecorated(true);

    // 表格不可编辑
    treeView->setEditTriggers(QAbstractItemView::NoEditTriggers);

    // 生成初始treeView数据
    initTreeData(treeView, m_treeModel);
}

void MainWindow::initTreeData(QStandardItemModel *treeModel)
{
    QStandardItem *treeRoot = m_treeModel->invisibleRootItem();

    for (int k=0; k<3; k++)
    {
        QStandardItem *nodeClass = new QStandardItem(QString("班级23-%1").arg(k + 1, 2, 10, QChar('0')));
        nodeClass->setIcon(QIcon(":/Images/iPhoto.png"));

        // 新增顶层节点(不可见的根节点之下)
        treeRoot->appendRow(nodeClass);

        for (int i = 0; i < 5; i++)
        {
            QList<QStandardItem *> studentInClass;

            for (int j=0; j<treeModel->columnCount(); j++)
            {
                QStandardItem *item = new QStandardItem;

                item->setTextAlignment(Qt::AlignRight);
                item->setData(QVariant(QString("col %1").arg(j)), Qt::UserRole + 1);

                if (j == 0)
                    item->setIcon(QIcon(":/Images/Automator.png"));

                if (j == 0)
                    item->setText(QString("name %1").arg(QRandomGenerator::global()->bounded(100, 1000)));
                else if (j == 1)
                    item->setText(QString("%1").arg(QRandomGenerator::global()->bounded(60, 150)));
                else if (j == 2)
                    item->setText(QString("%1").arg(QRandomGenerator::global()->bounded(60, 150)));
                else if (j == 3)
                    item->setText(QString("%1").arg(QRandomGenerator::global()->bounded(60, 150)));

                studentInClass.append(item);
            }

            // 班级下新增学生节点
            nodeClass->appendRow(studentInClass);
        }
    }
}

4.2. 遍历节点

4.2.1 以Model方式遍历

从上往下遍历某节点下的所有子节点。

void MainWindow::treeTraverse(QTreeView *treeView, QModelIndex &parentIndex)
{
    if (!parentIndex.isValid())
        return;

    QStandardItemModel *model = static_cast<QStandardItemModel *>(treeView->model());

    // 获取父节点下的行数
    int rowCount = treeView->model()->rowCount(parentIndex);

    for (int i=0; i<rowCount; i++)
    {
        QModelIndex childIndex   = model->index(i, 0, parentIndex);
        QStandardItem *childItem = model->itemFromIndex(childIndex);

        // 访问子节点
        qDebug() << model->data(childIndex); // 默认获取Qt::DisplayRole
        qDebug() << childItem->data();       // 默认获取用户私有数据 Qt::UserRole+1

        // 递归子节点
        if (model->hasChildren(childIndex))
            treeTraverse(treeView, childIndex);
    }
}

void MainWindow::do_treeDemoTraverse()
{
    // 循环遍历顶层节点
    for (int i=0; i<m_treeModel->rowCount(); i++)
    {
        // 取得顶层节点索引
        QModelIndex index = m_treeModel->index(i, 0);
        treeTraverse(ui->treeView, index);
    }
}

4.2.2. 以Item方式遍历

void MainWindow::do_treeDemoTraverse2()
{
    // 传入根节点QStandardItem指针
    treeTraverse2(m_treeModel->invisibleRootItem());
}

void MainWindow::treeTraverse2(QStandardItem *parentNode)
{
    if (!parentNode)
        return;

    for (int i = 0; i < parentNode->rowCount(); i++)
    {
        QStandardItem *child = parentNode->child(i);

        // 二者等效
        qDebug() << child->text();
        qDebug() << child->data(Qt::DisplayRole);
        if (child->hasChildren())
            treeTraverse2(child);
    }
}

4.3. 反向访问

由下往上遍历某节点的父系节点,直到根节点。

void MainWindow::treeTraverseBackward(QStandardItemModel *model, QModelIndex &index)
{
    if (!index.isValid())
        return;

    //访问数据
    qDebug() << model->data(index);

    QModelIndex parentIndex = index.parent();
    while (parentIndex.isValid())
    {
        qDebug() << model->data(parentIndex);
        parentIndex = parentIndex.parent();
    }
}

4.4. 磁盘目录建树

设定根目录,检索目录下的所有子目录以及文件,对所有子目录建立目录节点,对所有子目录再进行递归,对文件建立文件节点,文件节点无下级因此无需递归。整个目录递归完成后即可完成生成目录树。


```c++
//参数为主函数中添加的item和路径名
void MainWindow::addAllFiles(QStandardItem *parentNode, QString path)
{
    if (!parentNode)
        return;

    QDir dir(path);         //遍历各级子目录
    QDir dirFiles(path);    //遍历子目录中所有文件

    // 先遍历文件夹 添加进widget
    // fileList将保存root下面所有文件(包含子目录下的文件)
    QFileInfoList fileList   = dir.entryInfoList(QDir::Files);
    QFileInfoList folderList = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);

    for (int i = 0; i != folderList.size(); i++)      //自动递归添加各目录到上一级目录
    {
        QString   dirPath = folderList.at(i).absoluteFilePath(); //获取目录绝对路径
        QFileInfo dirInfo = folderList.at(i);
        QString   dirName = dirInfo.fileName();      // 获取短目录名

        QStandardItem *childItem = new QStandardItem(QIcon(":/Images/Open.png"), dirName);
        childItem->setData(QVariant(dirPath));  // 绝对路径放入私有数据 Qt::UserRole + 1
        parentNode->appendRow(childItem);       // 将当前短目录名添加成path的子项

        // 递归子文件夹
        addAllFiles(childItem, dirPath);
    }

    // 添加当前目录(parentNode)下的所有直接文件
    QStringList suffixFilter;
    //suffixFilter << "*.txt" << "*.c" << "*.h" << "*.go" << "*.py" << "*.cpp" << "*.hpp";
    suffixFilter << "*.*";
    QFileInfoList filesInCurrDir = dirFiles.entryInfoList(suffixFilter, QDir::Files, QDir::Name);
    for (int i=0; i<filesInCurrDir.size(); i++)
    {
        //将当前目录中所有文件添加到treeView中
        QFileInfo fi = filesInCurrDir.at(i);
        QString shortName = fi.fileName();
        QStandardItem *childItem = new QStandardItem(QIcon(":/Images/Open.png"), shortName);
        childItem->setIcon(QIcon(":/Images/New.png"));
        childItem->setText(shortName);
        childItem->setData(QVariant(fi.absoluteFilePath()));
        parentNode->appendRow(childItem);  // parentNode下添加所有文件
    }
}

// dirName: 目录全路径名
void MainWindow::openFolder(QString &dirName)
{
    QDir dir(dirName);

    if (dir.exists())
    {
        QFileInfo fi(dirName);

        QStandardItem *item = new QStandardItem(QIcon(":/Images/Open.png"), fi.fileName());

        item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable |
                       Qt::ItemIsEnabled | Qt::ItemIsAutoTristate);

        // 绝对路径存入Qt::UserRole + 1
        item->setData(QVariant(dirName));

        // 添加顶层节点
        m_treeModel->appendRow(item);

        // 顶层节点下添加所有子目录与文件
        addAllFiles(item, dirName);

        ui->treeView->expandAll();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值