现在的位置: 首页 > 综合 > 正文

Qt Model/View(转)1-2

2014年02月19日 ⁄ 综合 ⁄ 共 3924字 ⁄ 字号 评论关闭

Qt Model/View 学习笔记 (一)

介绍

Qt 4推出了一组新的item view类,它们使用model/view结构来管理数据与表示层的关系。这种结构带来的
功能上的分离给了开发人员更大的弹性来定制数据项的表示,它也提供一个标准的model接口,使得更多的
数据源可以被这些item view使用。这里对model/view的结构进行了描述,结构中的每个组件都进行了解释,
给出了一些例子说明了提供的这些类如何使用。

Model/View  结构

Model-View-Controller(MVC), 是从Smalltalk发展而来的一种设计模式,常被用于构建用户界面。经典设计模式的著作中有这样的描述:

MVC 由三种对象组成。Model是应用程序对象,View是它的屏幕表示,Controller定义了用户界面如何对用户输入进行响应。在MVC之前,用户界面设计倾向于三者揉合在一起,MVC对它们进行了解耦,提高了灵活性与重用性。

假如把view与controller结合在一起,结果就是model/view结构。这个结构依然是把数据存储与数据表示进行了分离,它与MVC
都基于同样的思想,但它更简单一些。这种分离使得在几个不同的view上显示同一个数据成为可能,也可以重新实现新的view,而不必改变底层的数据结
构。为了更灵活的对用户输入进行处理,引入了delegate这个概念。它的好处是,数据项的渲染与编程可以进行定制。

如上图所示,model与数据源通讯,并提供接口给结构中的别的组件使用。通讯的性质依赖于数据源的种类
与model实现的方式。view从model获取model indexes,后者是数据项的引用。通过把model indexes提供给model,view可以从数据源中获取数据。

在标准的views中,delegate会对数据项进行渲染,当某个数据项被选中时,delegate通过model
indexes与model直接进行交流。总的来说,model/view
相关类可以被分成上面所提到的三组:models,views,delegates。这些组件通过抽象类来定义,它们提供了共同的接口,在某些情况下,还
提供了缺省的实现。抽象类意味着需要子类化以提供完整的其他组件希望的功能。这也允许实现定制的组件。models,views,delegates之间
通过信号,槽机制来进行通讯:

从model发出的信号通知view数据源中的数据发生了改变。
从view发出的信号提供了有关被显示的数据项与用户交互的信息。
从delegate发生的信号被用于在编辑时通知model和view关于当前编辑器的状态信息。

Models

所有的item models都基于QAbstractItemModel
类,这个类定义了用于views和delegates访问数据的接口。
数据本身不必存储在model,数据可被置于一个数据结构或另外的类,文件,数据库,或别的程序组件中。
关于model的基本概念在Model Classes部分中描述。
QAbstractItemModel
提供给数据一个接口,它非常灵活,基本满足views的需要,无论数据用以下任何样的形式
表现,如tables,lists,trees。然而,当你重新实现一个model时,如果它基于table或list形式的数据结构,最好从QAbstractListModel
,QAbstractTableModel
开始做起,因为它们提供了适当的常规功能的缺省实现。这些类可以被子类化以支持特殊的定制需求。子类化model的过程在Create New Model部分讨论
QT提供了一些现成的models用于处理数据项:
QStringListModel
用于存储简单的QString列表。
QStandardItemModel
管理复杂的树型结构数据项,每项都可以包含任意数据。
QDirModel
  提供本地文件系统中的文件与目录信息。
QSqlQueryModel
, QSqlTableModel
,QSqlRelationTableModel
用来访问数据库。
假如这些标准Model不满足你的需要,你应该子类化QAbstractItemModel
,QAbstractListModel
或是
QAbstractTableModel
来定制。

Views

不同的view都完整实现了各自的功能:QListView
把数据显示为一个列表,QTableView
把Model 中的数据以table的形式表现,QTreeView
用具有层次结构的列表来显示model中的数据。这些类都基于QAbstractItemView
抽象基类,尽管这些类都是现成的,完整的进行了实现,但它们都可以用于子类化以便满足定制需求。

Delegates

QAbstractItemDelegate
是model/view架构中的用于delegate的抽象基类。缺省的delegate实现在QItemDelegate
类中提供。它可以用于Qt标准views的缺省 delegate.

排序

在model/view架构中,有两种方法进行排序,选择哪种方法依赖于你的底层Model。
假如你的model是可排序的,也就是它重新实现了QAbstractItemModel
::sort
()函数,QTableView
QTreeView
都提供了API,允许你以编程的方式对Model数据进行排序。另外,你也可以进行交互方式下的排序(例如,允许用户通过点击view表头的方式对数据进行排序),可以这样做:把QHeaderView
::sectionClicked
()信号与QTableView::sortByColum
()槽或QTreeView::sortByColumn
()槽进行联结就好了。
另一种方法是,假如你的model没有提供需要的接口或是你想用list view表示数据,可以用一个代理
model在用view表示数据之前对你的model数据结构进行转换。

便利类

许多便利类都源于标准的view类,它们方便了那些使用Qt中基于项的view与table类,它们不应该被子类化,
它们只是为Qt 3的等价类提供一个熟悉的接口。这些类有QListWidget,QTreeWidget,QTableWidget
,它们提供了如Qt 3中的QListBox, QlistView,QTable
相似的行为。这些类比View类缺少灵活性,不能用于任意的models,推介使用model/view的方法处理数据。

 

Qt Model/View 学习笔记 (二)

介绍

Qt提供了两个标准的models:QStandardItemModel
QDirModel
QStandardItemModel
是一个多用途的
model,可用于表示list,table,tree views所需要的各种不同的数据结构。这个model也持有数据。QDirModel

维护相关的目录内容的信息,它本身不持有数据,仅是对本地文件系统中的文件与目录的描述。
QDirModel
是一个现成的model,很容易进行配置以用于现存的数据,使用这个model,可以很好地展示如何
给一个现成的view设定model,研究如何用model indexes来操纵数据。

model与views的搭配使用

QListView
QTreeView
很适合与QDirModel
搭配。下面的例子在tree view与list view显示了相同的信息,QDirModel
提供了目录内容数据。这两个Views共享用户选择,因此每个被选择的项在每个view中都会被高亮。

先装配出一个QDirModel
以供使用,再创建views去显示目录的内容。这给我展示了使用model的最简单的方式。
model的创建与使用都在main()函数中完成:
 int main(int argc, char *argv[])
 {
     QApplication
app(argc, argv);
     QSplitter
*splitter = new QSplitter
;

     QDirModel
*model = new QDirModel
;
    //从缺省目录创建数据

     QTreeView
*tree = new QTreeView
(splitter);
     tree->setModel
(model);
     tree->setRootIndex
(model->index
(QDir::currentPath()));

     QListView
*list = new QListView
(splitter);
     list->setModel
(model);
     list->setRootIndex
(model->index
(QDir::currentPath()));
     //配置一个view去显示model中的数据,只需要简单地调用setModel(),并把目录model作为参数传递
     //setRootIndex()告诉views显示哪个目录的信息,这需要提供一个model index,然后用这个
     //model index去model中去获取数据
     //index()这个函数是QDirModel特有的,通过把一个目录做为参数,得到了需要的model index
     //其他的代码只是窗口show出来,进入程序的事件循环就好了

      splitter->setWindowTitle("Two views onto the same directory model");
     splitter->show
();
     return app.exec
();
 }

 

抱歉!评论已关闭.