Qt 之 QHeaderView 自定义排序(获取正确的 QModelIndex)

作者: 一去、二三里
个人微信号: iwaleon
微信公众号: 高效程序员

前几节中分享过关于自定义排序的功能,貌似我们之前的内容已经可以很好地解决排序问题了,但是,会由此引发一些很难发现的问题。。。比如:获取QModelIndex索引错误。

下面,我们先来实现一个整行选中的效果。

错误处理

效果

下面是一个非正常的的效果,选中当前行会造成更新错误,Why?

这里写图片描述

源码

// 连接信号槽
connect(pTableView, SIGNAL(clicked(QModelIndex)), this, SLOT(onClicked(QModelIndex)));

// 实现选中/不选
void MainWindow::onClicked(const QModelIndex &index)
{
    if (index.isValid())
    {
        // 获取复选框所在的索引
        QModelIndex checkIndex = m_pModel->index(index.row(), CHECK_BOX_COLUMN);
        // 获取复选框选中状态值
        bool bChecked = m_pModel->data(checkIndex, Qt::UserRole).toBool();
        // 更新复选框状态
        m_pModel->setData(checkIndex, !bChecked, Qt::UserRole);
    }
}

分析

从上面的代码中,我们貌似很难发现问题,因为逻辑没有一点问题,那么为什么会造成更新错误的问题呢?其实,最本质的原因是获取索引错误,这里说的索引是指真正的数据源索引,而并非我们看到的选中的索引。

什么意思呢?举个例子,如果我们选中的索引为QModelIndex(1, 0)-上图对应的路径是D:/Qt/image_4.png,因为该索引是我们选中的,也就是排序之后的索引,当我们按照正常思维去更新model的时候,传递的索引也是index(1, 0),这时数据源内部是未经过排序的,也就是说QModelIndex(1, 0)所对应的路径为E:/Qt/image_2.png,所以会造成更新错误。

如果说你没发现问题,那么只能说纯属偶然,源数据的索引行和你选中的索引行相同。

正常处理

效果

这里写图片描述

源码

这里,至关重要的代码mapToSource-通过选中的索引获取数据源对应的索引。

// 连接信号槽
connect(pTableView, SIGNAL(clicked(QModelIndex)), this, SLOT(onClicked(QModelIndex)));

// 实现选中/不选
void MainWindow::onClicked(const QModelIndex &index)
{
    if (index.isValid())
    {
	    // 获取数据源对应的索引 - 关键
        QModelIndex sourceIndex = m_pProxyModel->mapToSource(index);
        // 获取复选框所在的索引
        QModelIndex checkIndex = m_pModel->index(sourceIndex.row(), CHECK_BOX_COLUMN);
        // 获取复选框选中状态值
        bool bChecked = m_pModel->data(checkIndex, Qt::UserRole).toBool();
        // 更新复选框状态
        m_pModel->setData(checkIndex, !bChecked, Qt::UserRole);
    }
}
QHeaderView 是一个用于显示表格头部信息的控件,它支持多层表头。如果需要实现多层表头,可以使用 QStandardItemModel 来创建一个有层次结构的表格模型,然后将这个模型设置给 QTableView 控件。然后,QHeaderView 控件就可以根据这个模型来显示多层表头。 下面是一个简单的示例代码,演示如何使用 QStandardItemModelQTableView 实现多层表头: ```cpp QStandardItemModel *model = new QStandardItemModel(); // 设置列数和行数 model->setColumnCount(3); model->setRowCount(2); // 设置第一层表头 model->setHeaderData(0, Qt::Horizontal, "A"); model->setHeaderData(1, Qt::Horizontal, "B"); model->setHeaderData(2, Qt::Horizontal, "C"); // 设置第二层表头 QList<QStandardItem*> secondHeaders; for (int i = 0; i < 3; i++) { QStandardItem *item = new QStandardItem(); item->setData("Sub" + QString::number(i), Qt::DisplayRole); secondHeaders.append(item); } model->insertRow(0, secondHeaders); QTableView *tableView = new QTableView(); tableView->setModel(model); // 设置表头控件 QHeaderView *headerView = new QHeaderView(Qt::Horizontal, tableView); headerView->setSectionsClickable(true); headerView->setSectionResizeMode(QHeaderView::Stretch); tableView->setHorizontalHeader(headerView); // 显示表格 tableView->show(); ``` 在这个示例中,我们首先创建了一个 QStandardItemModel 对象,并设置了两层表头。第一层表头包含了三个列,显示为 "A"、"B" 和 "C"。第二层表头包含了三个子列,显示为 "Sub0"、"Sub1" 和 "Sub2"。 然后,我们创建了一个 QTableView 控件,并将我们创建的模型设置给它。接着,我们创建了一个 QHeaderView 控件,并将它设置为水平表头。最后,我们将这个表头控件设置给 QTableView 控件,然后显示表格。 这样,我们就实现了一个带有多层表头的表格。如果需要更复杂的表头结构,可以继续使用 QStandardItemModel 来创建更深层次的表格模型。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一去丶二三里

有收获,再打赏!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值