QT <Demo> Model/View

QT Model/View

毕业后一直从事Qt客户端开发,几年下来也踩了不少坑,现如今想通过 QT Demo 系列文章 以Demo程序的方式记录下所学所得。


前言

Model/View Qt文档描述:
Qt contains a set of item view classes that use a model/view architecture to manage the relationship between data and the way it is presented to the user.
The separation of functionality introduced by this architecture gives developers greater flexibility to customize the presentation of items, and provides a standard model interface to allow a wide range of data sources to be used with existing item views.
翻译:
Qt包含一组项目视图类,这些项目视图类使用模型/视图体系结构来管理数据与其呈现给用户的方式之间的关系。
此体系结构引入的功能分离为开发人员提供了更大的灵活性,可以自定义项目的表示形式,并提供标准的模型接口,以允许将各种数据源与现有项目视图一起使用。

一、Model

Qt提供两种标准模型是 QStandardItemModel 和 QFileSystemModel。

1 QStandardItemModel

QStandardItemModel is a multi-purpose model that can be used to represent various different data structures needed by list, table, and tree views. This model also holds the items of data
QStandardItemModel 是一个多用途模型,可用于表示列表、表和树视图所需的各种不同数据结构。 该模型还包含数据项

2 QFileSystemModel

QFileSystemModel is a model that maintains information about the contents of a directory. As a result, it does not hold any items of data itself, but simply represents files and directories on the local filing system
QFileSystemModel 是一个模型,用于维护有关目录内容的信息。 因此,它本身不保存任何数据项,而只是表示本地文件系统上的文件和目录

3 model 基类均为QAbstractItemModel

在这里插入图片描述

二、Delegate

实现自定义数据在View中呈现方式,实现自定义用户对View操作响应

1.QStyledItemDelegate 与 QItemDelegate

1>两者基类均为QAbstractItemDelegate
在这里插入图片描述2> 默认使用QStyledItemDelegate ,QStyledItemDelegate 使用当前样式绘制,并且能够使用 Qt Style Sheet,
3>QItemDelegate 与QStyledItemDelegate 区别只是是否支持Qt Style Sheet

三、View

QT 文档:
Qt provides three ready-to-use view classes that present data from models in ways that are familiar to most users. QListView can display items from a model as a simple list, or in the form of a classic icon view. QTreeView displays items from a model as a hierarchy of lists, allowing deeply nested structures to be represented in a compact way. QTableView presents items from a model in the form of a table, much like the layout of a spreadsheet application.
翻译:
Qt 提供了三个随时可用的视图类,它们以大多数用户熟悉的方式呈现来自模型的数据。 QListView 可以将模型中的项目显示为简单列表,或以经典图标视图的形式显示。 QTreeView将模型中的项目显示为列表的层次结构,从而以紧凑的方式表示深层嵌套的结构。
QTableView 以表格的形式呈现模型中的项目,很像电子表格应用程序的布局。

四、示例——QTableview

1、 Model 类

提供表格显示数据

<1> 表格数据结构

class PrivateData
{
public:
    QStringList strRows;//行表头
    QStringList strCols;//列表头
    QVector<QStringList> vIDatas;//数据
};
 PrivateData * d_Data;

<2> 数据更新

     void updateRows(QStringList rows);
     void updatecols(QStringList cols);
     void updateData(QVector<QStringList> datas);
     /**
 * @brief SubTableModel::updateRows
 * @param rows  表头名称
 */
void SubTableModel::updateRows(QStringList rows)
{
    if (!rows.isEmpty())
    {
        d_Data->strRows = rows;
    }
}
/**
 * @brief SubTableModel::updatecols
 * @param cols 表头名称
 */
void SubTableModel::updatecols(QStringList cols)
{
    if (!cols.isEmpty())
    {
        d_Data->strCols = cols;
    }
}
/**
 * @brief SubTableModel::updateData
 * @param datas 表格数据
 */
void SubTableModel::updateData(QVector<QStringList> datas)
{
    if(!datas.isEmpty())
    {
        d_Data->vIDatas.clear();
        d_Data->vIDatas= datas;
    }
}

<3> 重写headerData函数

根据role 返回表头数据和设置表头参数,

(1) 返回表头数据
	if(role == Qt::DisplayRole)
    {
        QString data;
        if(orientation == Qt::Vertical)
        {
            if(section < d_Data->strRows.size())
            {
                data= d_Data->strRows[section];
            }
        }
        else if(orientation == Qt::Horizontal)
        {
            if(section < d_Data->strCols.size())
            {
                data= d_Data->strCols[section];
            }
        }
        if(!data.isEmpty())
        {
            return data;
        }
        else
            return  QVariant();
    }
(2) 设置字体颜色
//2、文字颜色
    else if(role == Qt::ForegroundRole)
    {
        if(section % 2 == 0 )
        {
            return  QColor(Qt::cyan);
        }
        else
            return  QColor(Qt::darkCyan);
    }

<4> 重写rowCount返回行数

int SubTableModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;

    // FIXME: Implement me!
    return d_Data->strRows.size();
}

<5> 重写rowCount返回列数


int SubTableModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;

    // FIXME: Implement me!
    return d_Data->strCols.size();
}

<6> 重写data函数 返回当前刷新单元格数据

根据role 返回当前刷新单元格数据

(1) 单元格数据返回
//1、显示数据
    if(role == Qt::DisplayRole)
    {
        if(index.row() < d_Data->vIDatas.size() )
        {
            QStringList rowDatas= d_Data->vIDatas[index.row()];

            if(index.column() < rowDatas.size())
            {
                return  rowDatas[index.column()];
            }
            else
                return  QVariant();
        }
        else
            return  QVariant();
    }
(2) 奇偶行背景颜色交替
 //2、奇偶行背景颜色交替
    else if(role == Qt::BackgroundRole)
    {
        if(index.row() %2 == 0)
        {
            return  QColor(Qt::gray);
        }
        else
            return  QColor(Qt::darkGray);
    }

<7> QTableView 使用Model

 m_pView = new QTableView;
    this->setCentralWidget(m_pView);

    m_pView->horizontalHeader()->setVisible(true);
    m_pView->verticalHeader()->setVisible(true);

    m_pModel = new SubTableModel;
    updateTable();//model 数据
     m_pView->setEditTriggers(QAbstractItemView::DoubleClicked);
    m_pView->setModel(m_pModel);

<8> 显示效果

在这里插入图片描述

2、Delegate类

<1>重写 Model 类flags,让表格可编辑

Qt::ItemFlags SubTableModel::flags(const QModelIndex &index) const
{
    if(index.column() != 3)
          return Qt::ItemIsEnabled|Qt::ItemIsEditable;
    else
        return Qt::ItemIsEnabled;
}

<2>用QWidget 响应用户编辑

本例 中子类化QStyledItemDelegate实现,并指定第5列使用该Delegate类,第一行下拉框选择数据 其他行选择日期。

(1) 重写createEditor函数 返回控件用于用户编辑数据

用户选择日期和下拉选择数据项为例:

QWidget *SubItemItemDelegateWgt::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    int iRow = index.row();
    if( iRow == 1)
    {
     QComboBox *combox = new  QComboBox(parent);
     combox->setFrame(false);
     combox->addItem("com1");
     return  combox;
    }
    else
    {
        QDateEdit *dateedit = new QDateEdit(parent);
         dateedit->setFrame(false);
         return  dateedit;
    }
}
(2) 重写setEditorData函数用户编辑时控件数据
 int iRow = index.row();
    QWidget *pWgt = nullptr;
    if( iRow == 1)
    {
     QComboBox *combox= qobject_cast<QComboBox*>(editor);
     if(combox == nullptr)
     {
         return;
     }
     QString text = index.model()->data(index,Qt::DisplayRole).toString();
     combox->addItem(text);
    }
    else
    {
        QDateEdit *dateedit= qobject_cast<QDateEdit*>(editor);
        if(dateedit == nullptr)
        {
            return;
        }
       QString text = index.model()->data(index,Qt::DisplayRole).toString();
    }
(3) 重写setModelData函数用户编辑数据放入Model 中
1)Delegate 中setModelData函数:
void SubItemItemDelegateWgt::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{

    if(index.row() == 1 )
    {
        QComboBox *combox= qobject_cast<QComboBox*>(editor);

        if(combox == nullptr)
        {
            return;
        }

        model->setData(index,combox->currentText(),Qt::DisplayRole);
    }
    else
    {
        QDateEdit *dateedit= qobject_cast<QDateEdit*>(editor);

        if(dateedit == nullptr)
        {
            return;
        }
        QString date=  dateedit->date().toString("yyyy_MM_dd");
        model->setData(index,date,Qt::DisplayRole);
    }
}
2)Model类 中setData函数:
bool SubTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (index.isValid() && role == Qt::DisplayRole) {

        const int row = index.row();
          d_Data->vIDatas[row][index.column()] = value.toString();
           //发送信号触发刷新
           emit dataChanged(index, index, QVector<int>() << role);
           return true;
       }
       return false;
}
(4)重写 updateEditorGeometry 、sizeHint编辑控件大小

控件大小除了在delegate 通过sizeHint 返回外,还可以在model data函数中 case Qt::SizeHintRole:返回( 若发现 case Qt::SizeHintRole应在更新数据后 ui.tableView->resizeRowsToContents();)

void SubItemItemDelegateWgt::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
        editor->setGeometry(option.rect);
}

QSize SubItemItemDelegateWgt::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
        return QSize(100,50);
}

<3>单元格绘制图片

(1) 重写paint函数
void SubItemItemDelegatePaint::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    painter->save();
    QIcon icon("://icon/datarule.png");
    QSize iconsize = option.decorationSize;

    painter->drawPixmap(option.rect.x(),option.rect.y(), icon.pixmap(iconsize.width(), iconsize.height()));
    painter->restore();
}

<4>指定表格列使用Delegate

  m_pDelegate = new SubItemItemDelegateWgt;

    m_pView->setItemDelegateForColumn(4,m_pDelegate);

    m_pDelegatePaint = new SubItemItemDelegatePaint;
    m_pView->setItemDelegateForColumn(3,m_pDelegatePaint);

<5>显示效果

在这里插入图片描述

3、数据刷新

数据更新了表格并未更新数据,硬调用函数:
beginResetModel();
Qt 文档;A reset operation resets the model to its current state in any attached views
重置操作将模型在任何附加视图中重置为其当前状态
endResetModel();
Qt文档:
Completes a model reset operation.
You must call this function after resetting any internal data structure in your model or proxy model.完成一个模型重置操作
你必须在重置你的模型或代理模型中的任何内部数据结构后调用这个函数。

总结

重写(覆盖):是指派生类中存在重新定义的函数。其函数名,参数列表,返回值类型,所有都必须同基类中被重写的函数一致
重载:在同一个作用域内,两函数的函数名可以相同,但是参数不能完全相同

Demo 工程链接:
https://download.csdn.net/download/jiang173707/19811595?spm=1001.2014.3001.5501

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值