Qt模型/视图原理(1):基本理论

Qt模型/视图原理(1):基本理论

本文为原创文章,转载请注明出处,或注明转载自“黄邦勇帅(原名:黄勇)

本文出自本人原创著作《Qt5.10 GUI完全参考手册》网盘地址:
https://pan.baidu.com/s/1iqagt4SEC8PUYx6t3ku39Q
《C++语法详解》网盘地址:https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg

若对C++语法不熟悉,建议参阅本人所著《C++语法详解》一书,电子工业出版社出版,该书语法示例短小精悍,对查阅C++知识点相当方便,并对语法原理进行了透彻、深入详细的讲解,可确保读者彻底弄懂C++的原理,彻底解惑C++,使其知其然更知其所以然。此书是一本全面了解C++不可多得的案头必备图书。

数据通常由若干个数据项(item)组成。
MVC把需要处理的数据及其显示分离开来。MVC把图形界面分为三个部分:模型(Model)、视图(View)、控制器(Controller)。
 模型:用于管理数据,注意,数据不一定需要位于模型之中
 视图:就是呈现在用户面前的界面外观,视图负责把模型中的数据显示给用户。
 控制器:用于处理用户在用户界面的输入。
1、Qt实现的MVC模型(见图8-4)
在这里插入图片描述
Qt把视图和控制器组合在一起,从而形成模型/视图结构。模型直接与数据进行通信,并为视图和委托提供访问数据的接口。
数据与模型:数据不一定需要存储在模型中,数据也可以存储在文件、数据库等其他地方,存储的数据不一定拥有一种数据结构,但是模型通常会把这些数据组织成一种数据结构(比如列表(list)结构、树形(tree结构等),这种结构只是逻辑上的结构,数据本身不一定拥有这种结构,然后视图根据模型提供的逻辑结构显示数据,比如列表视图(QListView)可以显示把数据组织成列表结构的模型(QStandardItemModel模型实现了该种结构)中的数据;当然,也可以使用列表视图显示组织为树形结构的数据,但这样做需要做一些比较麻烦的处理才能正确显示,所以通常应使用列表视图显示列表模型的数据,树形视图显示树形结构模型的数据。
为了对用户的输入进行灵活的处理,Qt引入了委托Delegate(或代理)的概念,委托其实就是把用户输入的数据委托给Qt的某个部件处理,比如委托QSpinBox部件来处理用户输入的整数等。另外,委托还会绘制(或渲染)视图中的个别数据项。
模型、视图、委托之间的通信使用Qt的信号和槽机制来完成。
图8-5为实际的图形界面,MVC各部分间的功能如图8-5所示
在这里插入图片描述
2、Qt对模型/视图结构的具体实现
(1)、模型
Qt使用抽象类QAbstractItemModel来描述模型,所有的模型都是通过子类化该抽像类而实现的。Qt实现了一些标准的现成模型,下面是一简介:
 QStringListModel:用于存储QString项目的列表。
 QStandardItemModel:该模型可以被当作列表模型、表格模型、树模型来使用。
 QFileSystemModel:该模型提供本地文件系统中的文件和目录信息,模型本身没有任何的数据项目。
 QSqlQueryModel、QSqlTableModel、QSqlRelationalTableModel与数据库有关。
(2)、视图
Qt使用抽象类QAbstractItemView来描述视图,所有的视图都是通过子类化该抽像类而实现的。Qt实现了一些标准的现成视图,比如QListView(列表视图),QTableView(表格视图),QTreeView(树视图)等。
(3)、委托
Qt使用抽象类QAbstractItemDelegate来描述委托,Qt实现了两个委托类,QStyledItemDelegate和QItemDelegate,这两个委托之中只能使用其中一个,其区别在于QItemDelegate总是使用一种默认的样式绘制数据项,而QStyledItemDelegate使用当前的样式来绘制数据项,通常使用的是QStyledItemDelegate。Qt默认使用QStyledItemDelegate。
3、使用Qt模型/视图的步骤(见示例8.1)

示例8.1 显示一个简单的表格(界面见图8-6)
QStandardItemModel model(3,3,this); //创建一个3行3列的表格结构的模型
        QTableView v1;		 //创建一个表格视图
    //设置模型的数据,使用索引的形式设置每个数据项的值
        model.setData(model.index(0,0),123);
        model.setData(model.index(0,1),222);
        model.setData(model.index(0,2),333);
        model.setData(model.index(1,0),444);
        model.setData(model.index(1,1),555);
        model.setData(model.index(1,2),666);
        model.setData(model.index(2,0),777);
        model.setData(model.index(2,1),888);
        model.setData(model.index(2,2),999);
        v1.setModel(&model);  	//设置视图v1的模型
        v1.show();  			//显示视图

 
 

    在这里插入图片描述

    8.1.2 定位模型中的数据与模型索引
    1、模型的结构
    在Qt中,无论数据被存储为何种数据结构,模型总是以层次结构(即树形结构)来表示数据,视图按照此约定来访问模型中的数据,若数据是列表(list)或表格(tab)结构的数据,则可以把其看作是只含有顶层节点,不含任何子节点的树形结构。也就是说,我们在子类化QAbstractItemModel来自定义自已的模型结构时,始终应以树形结构为出发点,来组织自已的模型结构。
    2、模型索引(简称索引)
    Qt使用模型索引来使数据的表示和访问相分离,视图和委托使用索引来访问模型中的数据项,因此,只有模型知道怎样获取数据。
    模型索引不像普通索引仅使用一个数字就能描述,模型索引需要使用3个属性进行描述:行号、列号、父模型索引。虽然模型索引使用行号、列号来定位数据项,但这并不意味着,数据是存储在数组或表格结构中的,使用行号、列号只是允许模型与视图、代理进行通信的一种约定。之所以需要父模型索引,是因为Qt的模型都是以层次结构(树形结构)组织的,Qt具体实现时,顶级数据项的父模型索引,使用“无效模型索引”来表示。
    模型索引包含一个指向创建它们的模型的指针,当使用多个模型时,可避免混淆。
    3、Qt对模型索引的实现
    Qt使用QModelIndex类实现模型索引,该类提供的索引是一个临时索引,因为模型可能会随时重新组织其内部结构(即数据项可能随时发生变化,比如删除、增加新数据项等),因此模型索引可能会变得无效,所以模型索引不需要也不应被存储,若需要对数据项进行长时间的引用,应使用QPersistentModelIndex类创建一个持久模型索引。
    使用模型索引引用模型中数据项的方法是使用QAbstractItemModel::index()函数。
    无效模型索引使用零参数的QModelIndex类的构造函数创建,即QModelIndex()就表示创建了一个无效模型索引。
    4、下面以代码的形式来说明模型索引,图8-7为Qt常见的模型结构。
    在这里插入图片描述
    (1)、树形结构
    //获取数据项A的模型索引,A的父索引由一个无效模型索引指定。
    QModelIndex iA = model.index(0,0, QModelIndex());
    //获取数据项B的模型索引,B位于父索引iA的第1行第1列位置。
    QModelIndex iB = model.index(1,1, iA);
    (2)、表格结构
    //获取数据项B的模型索引,B是顶级数据项,因此其父索引是一个无效索引。
    QModelIndex iB = model.index(1,2, QModelIndex());
    (3)、列表结构
    //获取数据项B的模型索引,B是顶级数据项,因此其父索引是一个无效索引。
    QModelIndex iB = model.index(1,0, QModelIndex());

    8.1.3 数据的角色与数据的类型
    同一个类型的数据可以作为不同的角色(或作用)来使用,比如对于字符串"AAA",可把该字符串以文本的形式显示在视图的相应位置上,也可把该字符串作为工具提示使用,还可把该字符串作为what’s this的帮助提示等。由此可见,数据的角色,决定了该数据在视图中的显示方式,角色不同,显示方式也不同。
    数据项与数据元素:位于同一个位置的数据项,并不仅仅
    只有一个数据元素,本文把组成数据项的数据称为数据元素,每个数据元素都有其自身的角色,比如一个数据项可能会同时含有图标数据元素(角色为Qt::DecorationRole)、文本数据元素(角色为Qt::DisplayRole)、工具提示数据元素(角色为Qt::ToolTipRole)等(见图8-8第1行第2列的数据项"222")。
    在这里插入图片描述
    因为数据项由多个数据元素组成,因此把数据项使用一个单独的类来管理是比较方便的,比如对于QStandardItemModel模型的数据项,就使用了类QStandardItem来专门管理其数据项。
    为了避免概念上的混乱,下面对数据、数据项、项(项目)、节点、单元格、数据元素、模型索引(索引)做一简介
    ①、数据:是一个统称,既可以是数据项也可以是数据元素。
    ②、数据项:是由多个数据元素组成的,每个数据元素都有自已的角色。
    ③、单元格、节点、项目:这三个概念通常用于指模型中的某一个数据项所在的位置,只是对于不同的模型结构会有不同的称呼,比如树形结构通常称为节点,表格结构通常称为单元格,而项目是一种更通用的称呼,Qt中通常称其为项目(item)或数据项;有时也会对以上概念加以区别对待,比如单元格XXX的数据项,此时单元格表示位置,数据项就表示实际存储的数据。不管怎样,模型中某个数据项所在位置都是需要使用模型索引来指定的,因此单元格、节点、项目、数据项、模型索引这几个概念通常会根据不同的情形用于表示模型中的某个位置。
    标准的数据角色由枚举Qt::ItemDataRole来描述,见表8-1。数据角色由QAbstractItemModel::setData()函数的第3个参数指定,其使用方法如下,其效果见图8-8第1行第2列的单元格。

    model.setData(model.index(0,1),222,Qt::DisplayRole);    //设置显示的文本
    model.setData(model.index(0,1),QIcon("F:/1i.png"),Qt::DecorationRole);  //设置图标
    model.setData(model.index(0,1),"EEE",Qt::ToolTipRole);   //设置工具提示
    
     
     

    在这里插入图片描述

    8.1.4 选择视图中的数据项(选择模型)

    对视图内项目的选择Qt使用QItemSelectionModel类(选择模型)来实现。所有的标准视图都有自已默认的选择模型。视图可以使用QAbstractItemView::selectionModel()函数和QAbstractItemView::setSelectionModel()来获取和设置选择模型。通常不需要对选择模型进行设置。

    8.1.5 Qt实现的便利类

    Qt通过模型/视图框架结构实现了一些标准的方便使用的部件,使用这些便利部件更方便和简单,这些类是QListWidget、QTreeWidget、QTableWidget。

    本文作者:黄邦勇帅(原名:黄勇)

    在这里插入图片描述

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

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

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

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值