向QAbstractItemView子类如:QTreeView、QTableView等子项单元格插入窗体小部件的功能实现(第1种方法)

目录

1.前言

2.利用QAbstractItemView类的setIndexWidget函数实现

3.后记


1.前言

工作中经常会遇到这样的需求:向QAbstractItemView子类如QTreeView、QTableView单元格插入窗体小部件,如:进度条、按钮、单行编辑框等。下面链接的系列博文就是讲解如何实现该功能的。

这些系列博文所说的技术点适用于同时满足下面条件的所有类:

  • 模型类从 QAbstractItemModel派生。

  • 代理类从QStyledItemDelegate或QItemDelegate派生。

  • 视图类是QAbstractItemView的子类。

这些系列博文用到了Qt的model/view framework框架,如果对Qt的“模型/视图/代理”框架不懂,这些系列文章很难读懂。如果不懂这方面的知识,请在Qt Assistant 中输入Model/View Programming 学习了解。读者本机Qt安装目录下的Examples\Qt-XX.XX.XX\widgets\itemviews目录下有很多model/view framework的例子,可以进行自学了解,其中XX.XX.XX为Qt的版本号,如:5.14.1。

因为QColumnView、QHeaderView、QListView、QTableView、QTreeView、QListWidget 、QUndoView、QTableWidget、QTreeWidget都是从QAbstractItemView继承,故这些系列博文所说的技术点也适用于这些类。

本博文通过Qt的QAbstractItemView视图基类自带的函数来实现该功能。

2.利用QAbstractItemView类的setIndexWidget函数实现

QAbstractItemView类有个setIndexWidget函数,该函数声明如下:


void QAbstractItemView::setIndexWidget(const QModelIndex &index, QWidget *widget)

第1个参数是模型索引,你可以想象为就是一个单元格所在的行列索引号。如果该参数无效,例如是根节点索引时,则这个函数什么都不做。

第2个参数是单元格要插入的窗体部件。注意:窗体部件autoFillBackground 属性要设置为true,否则窗体背景色是透明的。如果在指定索引处的A窗体被后来的窗体B替换,则A窗体被删除,如下:


 
  setIndexWidget(index, new QLineEdit);
  ...
  setIndexWidget(index, new QTextEdit);

则QLineEdit会被删除。本函数仅仅能用来根据项的数据在可见区域显示一些静态内容,如果需要显示一些动态内容或者显示一个自定义的编辑框部件,需通过子类化QStyledItemDelegate类实现。

以QTableView为例子来说明。 为了给QTableView提供数据,必须实现一个模型即从QAbstractTableModel.类派生出自己的模型类来,模型类model.cpp代码如下:


#include "model.h"
CModel::CModel(QObject *parent)
    : QAbstractTableModel(parent)
{}
 
CModel::~CModel()
{}
 
QVariant CModel::data(const QModelIndex& index, int role/* = Qt::DisplayRole*/) const
{
    return QVariant();
}
 
// 作为例子,假想QTableView有2列
int CModel::columnCount(const QModelIndex& parent/* = QModelIndex()*/) const
{
    return 2;
}
 
// 作为例子,假想QTableView有88行
int CModel::rowCount(const QModelIndex& parent/* = QModelIndex()*/) const
{
    return 88;
}
 
QVariant CModel::headerData(int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole*/) const
{
    if (orientation != Qt::Horizontal) // 作为例子演示,我们只关心表头是水平的情况
        return QVariant();
 
    if (role != Qt::DisplayRole)// 作为例子演示,我们只关心 Qt::DisplayRole
        return QVariant();
 
    // 构造列,第1列列名为"button";第2列列名为"checkbox"
    if(0 == section)
     return "button";
    else if(1 == section)
        return "checkbox";
 
    return QVariant();
}

QtWidgetsApplication1.cpp实现如下:


#include "QtWidgetsApplication1.h"
#include "model.h"
#include<QPushButton>
#include<QScrollBar>
#include<QCheckBox>
QtWidgetsApplication1::QtWidgetsApplication1(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
 
    m_pModel = new CModel(this); // new出一个模型对象
    ui.tableView->setModel(m_pModel);// 将表格视图的模型对象设置为上步构建出来的模型对象

    installWidget();
}

void QtWidgetsApplication1::installWidget()
{
    auto nRowCount = m_pModel->rowCount();   // 获取表视图有多少行
    auto nColCount = m_pModel->columnCount();// 获取表视图有多少列
 
  // 表视图对象中的每行第0列插入一个QPushButton按钮,在第1列插入一个QCheckBox对象
    for (auto nRowIndx = 0; nRowIndx < nRowCount; ++nRowIndx)
    {
        auto modelIndx = m_pModel->index(nRowIndx, 0);
        QString qsText(QString("button%1").arg(nRowIndx));
        ui.tableView->setIndexWidget(modelIndx, new QPushButton(qsText, this));
 
        modelIndx = m_pModel->index(nRowIndx, 1);
        qsText = (QString("checkbox%1").arg(nRowIndx));
        ui.tableView->setIndexWidget(modelIndx, new QCheckBox(qsText, this));
    }
}
 

installWidget函数利用setIndexWidget函数在表视图对象中的每行第0列插入一个QPushButton按钮,在第1列插入一个QCheckBox对象。效果如下:

3.后记

如果是QTableWidget类,则也可以用如下函数插入窗体小部件:


void QTableWidget::setCellWidget(int row, int column, QWidget *widget)

如下代码:


setCellWidget(row, column, new QLineEdit);
setCellWidget(row, column + 1, new QTextEdit);

实现向第row行的column列和column+1列分别插入了一个QLineEdit和一个QTextEdit窗体小部件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值