Qt的Model/View结构

Model/View结构

将界面组件与所编辑的数据分离开来,又通过数据源的方式连接起来,是处理界面与数据的一种较好的方式。Qt使用Model/View结构来处理这种关系,Model/View的基本结构如图5-1所示。其中各部分的功能如下。

在这里插入图片描述
图1 Model/View基本结构(来自Qt帮助文件)

别人写的哪些都特别的麻烦,都不知道要讲什么意思,简单点讲。就是用了Model/View结构之后,我修改了界面上的数据就是同步修改了我Model中的数据,就是两者的数据是同步的。如果我们没有使用Model/View的结构,那么我们修改了界面上的组件的数据之后,只是我的组件中数据修改了,但是我给组件的原始数据是没有修改的,因此我们还得遍历组件的数据,让数据进行同步的处理,才可以。使用这个结构的好处就是,修改数据就是修改同步的数据。

在Model/View结构中,还提供了代理(Delegate)功能,代理功能可以让用户定制数据的界面显示和编辑方式。在标准的视图组件中,代理功能显示一个数据,当数据被编辑时,代理通过模型索引与数据模型通信,并为编辑数据提供一个编辑器,一般是一个QLineEdit组件。

模型、视图和代理之间使用信号和槽通信。当源数据发生变化时,数据模型发射信号通知视图组件;当用户在界面上操作数据时,视图组件发射信号表示这些操作信息;当编辑数据时,代理发射信号告知数据模型和视图组件编辑器的状态。

知道了Model/View是用来干嘛的。使用过程中我们需要理解的原理。

1.数据模型的基本结构

在Model/View结构中,数据模型为视图组件和代理提供存取数据的标准接口。在Qt中,所有的数据模型类都从QAbstractItemModel继承而来,不管底层的数据结构是如何组织数据的,QAbstractItemModel的子类都以表格的层次结构表示数据,视图组件通过这种规则来存取模型中的数据,但是表现给用户的形式不一样。

图是数据模型的3种常见表现形式。不管数据模型的表现形式是怎么样的,数据模型中存储数据的基本单元都是项(item),每个项有一个行号、一个列号,还有一个父项(parent item)。在列表和表格模式下,所有的项都有一个相同的顶层项(root item);在树状结构中,行号、列号、父项稍微复杂一点,但是由这3个参数完全可以定义一个项的位置,从而存取项的数据。

..\18-0113 图\0504.tif
图 数据模型的几种表现形式(来自Qt帮助文件)

2.模型索引

为了保证数据的表示与数据存取方式隔离,数据模型中引入了模型索引(model index)的概念。通过数据模型存取的每个数据都有一个模型索引,视图组件和代理都通过模型索引来获取数据。

QModelIndex表示模型索引的类。模型索引提供数据存取的一个临时指针,用于通过数据模型提取或修改数据。因为模型内部组织数据的结构随时可能改变,所以模型索引是临时的。如果需要使用持久性的模型索引,则要使用QPersistentModelIndex类。

3.行号和列号

数据模型的基本形式是用行和列定义的表格数据,但这并不意味着底层的数据是用二维数组存储的,使用行和列只是为了组件之间交互方便的一种规定。通过模型索引的行号和列号就可以存取数据。

要获得一个模型索引,必须提供3个参数:行号、列号、父项的模型索引。例如,对于如图5-4中的表格数据模型中的3个数据项A、B、C,获取其模型索引的代码是:

QModelIndex indexA = model->index(0, 0, QModelIndex());
QModelIndex indexB = model->index(1, 1, QModelIndex());
QModelIndex indexC = model->index(2, 1, QModelIndex());

在创建模型索引的函数中需要传递行号、列号和父项的模型索引。对于列表和表格模式的数据模型,顶层节点总是用QModelIndex()表示。

4.父项

当数据模型是列表或表格时,使用行号、列号存储数据比较直观,所有数据项的父项(parent item)就是顶层项;当数据模型是树状结构时,情况比较复杂(树状结构中,项一般习惯于称为节点),一个节点可以有父节点,也可以是其他节点的父节点,在构造数据项的模型索引时,必须指定正确的行号、列号和父节点。

对于图5-4中的树状数据模型,节点A和节点C的父节点是顶层节点,获取模型索引的代码是:

QModelIndex indexA = model->index(0, 0, QModelIndex());
QModelIndex indexC = model->index(2, 1, QModelIndex());

但是,节点B的父节点是节点A,节点B的模型索引由下面的代码生成:

QModelIndex indexB = model->index(1, 0, indexA);

5.项的角色

在为数据模型的一个项设置数据时,可以赋予其不同项的角色(item role)的数据。例如,数据模型类QStandardItemModel的项数据类是QStandardItem,其设置数据的函数是:

void QStandardItem::setData(const QVariant &value,int role= Qt::UserRole + 1)

其中,value是需要设置的数据,role是设置数据的角色。一个项可以有不同角色的数据,用于不同的场合。

role是Qt::ItemDataRole枚举类型,有多种取值,如Qt::DisplayRole 角色是在视图组件中显示的字符串,Qt::ToolTipRole是鼠标提示消息,Qt::UserRole可以自定义数据。项的标准角色是Qt::DisplayRole。

在获取一个项的数据时也需要指定角色,以获取不同角色的数据。

QVariant QStandardItem::data(int role = Qt::UserRole + 1) const

为一个项的不同角色定义数据,可以告知视图组件和代理组件如何显示数据。例如,在图5-5中,项的DisplayRole数据是显示的字符串,DecorationRole是用于装饰显示的属性,ToolTipRole定义了鼠标提示信息。不同的视图组件对各种角色数据的解释和显示可能不一样,也可能忽略某些角色的数据。

图片 134
图 不同角色数据的表现形式(来自Qt帮助文件)

使用Qt给我们已经准备好的model模型类

Qt中是已经帮我们写好了一些模型类的。我们可以与组件View进行组合就可以实现,model中的数据与组件View中的数据进行一个同步的结果。
使用Model/View的一般的步骤:
1.先建立自己我需要的xxxxModel类。
2.给xxxModel设置初始化,比如增加数据,设置目录等等。
3.给与Model匹配的View组件设置设置model。setModel()函数。
4.修改model中的数据就是等于修改了界面中数据,修改界面中的数据model中的数据也是修改的。

1.QFileSystemModel

QFileSystemModel类的基本功能

QFileSystemModel提供了一个可用于访问本机文件系统的数据模型。QFileSystemModel和视图组件QTreeView结合使用,可以用目录树的形式显示本机上的文件系统,如同Widnows的资源管理器一样。使用QFileSystemModel提供的接口函数,可以创建目录、删除目录、重命名目录,可以获得文件名称、目录名称、文件大小等参数,还可以获得文件的详细信息。

要通过QFileSystemModel获得本机的文件系统,需要用setRootPath()函数为QFileSystemModel设置一个根目录,例如:

QFileSystemModel *model = new QFileSystemModel;
model->setRootPath(QDir::currentPath());

静态函数QDir::currentPath()获取应用程序的当前路径。

用于获取磁盘文件目录的数据模型类还有一个QDirModel,QDirModel的功能与QFileSystemModel类似,也可以获取目录和文件,但是QFileSystemModel采用单独的线程获取目录文件结构,而QDirModel不使用单独的线程。使用单独的线程就不会阻碍主线程,所以推荐使用QFileSystemModel。

QFileSystemModel的使用

实例samp5_1的主窗口是基于QMainWindow的,在使用UI设计器做可视化设计时删除了工具栏和状态栏。主窗口界面布局采用了两个分割条的设计,ListView和TableView采用上下分割布局,然后和左边的TreeView采用水平分割布局,水平分割布局再和下方显示信息的groupBox在主窗口工作区水平布局。

在主窗口类中定义了一个QFileSystemModel类的成员变量model。
QFileSystemModel *model;
主窗口构造函数进行初始化,代码如下:

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
   
   
   ui->setupUi(this);
   model=new QFileSystemModel(this); 
   model->setRootPath(QDir::currentPath()); //设置根目录
   ui->treeView->setModel(model); //设置数据模型
   ui->listView->setModel(model); //设置数据模型
   ui->tableView->setModel(model); //设置数据模型
//信号与槽关联,treeView单击时,其目录设置为listView和tableView的根节点
   connect(ui->treeView,SIGNAL(clicked(QModelIndex)),
         ui->listView,SLOT(setRootIndex(QModelIndex)));
   connect(ui->treeView,SIGNAL(clicked(QModelIndex)),
         ui->tableView,SLOT(setRootIndex(QModelIndex)));
}

3个视图组件都使用setModel()函数,将QFileSystemModel数据模型model设置为自己的数据模型。

connect()函数设置信号与槽的关联,实现的功能是:在单击treeView的一个节点时,此节点就设置为listView和tableView的根节点,因为treeView的clicked(QModelIndex)信号会传递一个QModelIndex变量,是当前节点的模型索引,将此模型索引传递给listView和tableView的槽函数setRootIndex(QModelIndex),listView和tableView就会显示此节点下的目录和文件。

在treeView上单击一个节点时,下方的一些标签里会显示节点的一些信息,这是为treeView的clicked(const QModelIndex &index)信号编写槽函数实现的,其代码如下:

void MainWindow::on_treeView_clicked(const QModelIndex &index)
{
   
   
   ui->chkIsDir->setChecked(model->isDir(index)); //是否是目录
   ui->LabPath->setText(model->filePath(index));
   ui->LabType->setText(model->type(index));
   ui->LabFileName->setText(model->fileName(index));
   int sz=model->size(index)/1024;
   if (sz<1024)
      ui->LabFileSize->setText(QString("%1 KB").arg(sz));
   else
      ui->LabFileSize->setText(QString::asprintf("%.1f MB",sz/1024.0));
}

函数有一个传递参数QModelIndex &index,它是单击节点在数据模型中的索引。通过传递来的模型索引index,这段代码使用了QFileSystemModel的一些函数来获得节点的一些参数,包括以下几种。

bool isDir(QModelIndex &index):判断节点是不是一个目录。
QString filePath(QModelIndex &index):返回节点的目录名或带路径的文件名。
QString fileName(QModelIndex &index):返回去除路径的文件夹名称或文件名。
QString type(QModelIndex &index):返回描述节点类型的文字,如硬盘符是“Drive”,文件夹是“File Folder”,文件则用具体的后缀描述,如“txt File”“exe File”“pdf File”等。
qint64 size(QModelIndex &index):如果节点是文件,返回文件大小的字节数:如果节点是文件夹,返回0。
而QFileSystemModel是如何获取磁盘目录文件结构的,3个视图组件是如何显示这些数据的,则是其底层实现的问题了。

QStringListModel

这个模型是为了更好的显示出ListView的内容的,是跟ListView更好的匹配的。

1.QStringListModel功能概述

QStringListModel用于处理字符串列表的数据模型,它可以作为QListView的数据模型,在界面上显示和编辑字符串列表。

QStringListModel的setStringList()函数可以初始化数据模型的字符串列表的内容,stringList()函数返回数据模型内的字符串列表,在关联的ListView组件里编辑修改数据后,数据都会及时更新到数据模型内的字符串列表里。

QStringListModel提供编辑和修改字符串列表数据的函数,如insertRows()、removeRows()、setData()等,这些操作直接影响数据模型内部的字符串列表,并且修改后的数据会自动在关联的ListView组件里刷新显示。

2.QStringListModel的使用

1.Model/View结构对象和组件初始化

窗口是从QWidget继承而来的类Widget,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值