Qt视图模型(model/view)心得(转载)

原创地址 :https://blog.csdn.net/kiss_my_dream/article/details/78142633

概述

关于视图模型,Qt已经封装了几个方便我们使用的类:QListWidget、QTreeWidget和QTabWidget,这几个类特y点是使用起来很方便,适合显示比较简单的数据,若是涉及到大量的数据要显示、以及对性能要求严格就得用到视图模型了。 
这里写图片描述

模型

简单的说,模型是跟数据打交道的。以QAbstractListModel为例,我们需要子类化QAbstractListModel,并重写它提供的这几个函数:

int QAbstractItemModel::rowCount(const QModelIndex & parent = QModelIndex()) const
QVariant QAbstractItemModel::data(const QModelIndex & index, int role = Qt::DisplayRole) const
  • 1
  • 2

重写的rowCount函数功能是返回总行数,这里我们返回数据集(m_data)的长度

int MyModels::rowCount(const QModelIndex & parent) const {
    return m_data.count();
}
  • 1
  • 2
  • 3

data函数功能是给外部提供获取数据的接口,不过这个函数是系统自动调用的,我们只需要实现其功能即可

QVariant MyModels::data(const QModelIndex & index, int role) const {
    if (!index.isValid())
    {
        return QVariant();
    }

    int row = index.row();
    if (role == Qt::DisplayRole)
    {
        QString fileName = m_data[row];
        return fileName;
    }
    else if (role == Qt::DecorationRole)
    {
        return QPixmap("resources/music_icon.png"); // 为了方便,固定显示某张图片
    }

    return QVariant();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

每个item它可能包含不同的内容(图片、文字等),role的意义是为了区分这些不同的内容,一般来说,Qt::DisplayRole代表文字,Qt::DecorationRole代表图片,更多关于角色的内容大家可以去查看文档。假设数据集是歌曲列表,那么我们在Qt::DisplayRole里返回歌曲名,在Qt::DecorationRole里面返回歌曲的图片。 
注意: 
当数据发生变化时(添加、删除等),需要手动发送dataChanged信号通知视图更新界面。

emit dataChanged(topLeft,bottomRight)
  • 1

视图

视图负责把数据展示到界面上,这些数据是通过从模型中获取的。最简单的视图操作,我们只需把模型设置到视图上来就可以了。

QListView myListView;
myModels = new MyModels();
myListView.setModel(myModels);
  • 1
  • 2
  • 3

至此,我们就可以从界面上看到展示的数据了,但是我们无法操作这些数据,需要添加委托才能操作数据。

委托

只有模型和视图的话,用户是不能对视图上显示的内容做操作的,如果需要对视图内容进行操作或者是要在视图上显示比较复杂的item时就需要子类化委托(Delegate),并重写它的一些方法。下面列出常用的需要重写的几个方法:

QWidget * QAbstractItemDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const
void QAbstractItemDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const
void QAbstractItemDelegate::destroyEditor(QWidget * editor, const QModelIndex & index) const
  • 1
  • 2
  • 3

createEditor创建一个编辑器对象,这个对象是我们展现给用户去操作视图内容的对象,这里我创建了一个MyWidget对象,在MyWidget类添加要显示的控件以及操作的业务逻辑。

QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const{
    QWidget *myWidget = new MyWidget(parent); // MusicOperation为自己创建的QWidget类
    return myWidget;
}
  • 1
  • 2
  • 3
  • 4

我们重写委托的目的是为了操作视图上显示的数据的,而数据是由模型进行管理的,这里委托提供了一个方便的接口setEditorData,通过这个接口可以把模型里的数据设置到编辑器上,有了数据,我们就可以通过编辑器(界面)去修改数据了。

void MyDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const{
    editor->setItem(index.model()->m_data[index.row()], index);
}
  • 1
  • 2
  • 3

参数一为createEditor返回的widget,参数二为模型索引,通过这个参数可以取到数据集中的数据

我们在destroyEditor删除先前创建的编辑器widget。

void MyDelegate::destroyEditor(QWidget * editor, const QModelIndex & index) const{
    editor->deleteLater();
}
  • 1
  • 2
  • 3

最后,把委托关联到listview。

MyDelegate *delegate = new MyDelegate(parent);
myListView.setItemDelegate(delegate);
  • 1
  • 2

我们需要显式地调用视图的openPersistentEditor方法才能把编辑器加载出来

myListView.openPersistentEditor(index)
  • 1

它会自动调用我们重写的createEditor方法、setEditorData方法。同理,关闭编辑器调用closePersistentEditor就可以了,它会自动调用我们重写的destroyEditor方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值