250 likes | 486 Views
嵌入式应用软件开发. 模式、视图( Model 、 View )结构. www.gdsdxy.cn. 学习内容. 概念 模型( Models ) 视图( Views ) 代理( Delegates ). model/view 结构. Qt 4 推出了一组新的 item view 类,它们使用 model/view 结构来管理数据与表示层的关系。这种结构带来的功能上的分离给了开发人员更大的弹性来定制数据项的表示,它也提供一个标准的 model 接口,使得更多的数据源可以被这些 item view 使用。. Model/View 结构.
E N D
嵌入式应用软件开发 模式、视图(Model、View)结构 www.gdsdxy.cn
学习内容 • 概念 • 模型(Models) • 视图(Views) • 代理(Delegates)
model/view结构 • Qt 4推出了一组新的item view类,它们使用model/view结构来管理数据与表示层的关系。这种结构带来的功能上的分离给了开发人员更大的弹性来定制数据项的表示,它也提供一个标准的model接口,使得更多的数据源可以被这些item view使用。
Model/View 结构 • Model-View-Controller(MVC), 是从Smalltalk发展而来的一种设计模式,常被用于构建用户界面。经典设计模式的著作中有这样的描述: • MVC 由三种对象组成。Model是应用程序对象,View是它的屏幕表示,Controller定义了用户界面如何对用户输入进行响应。在MVC之前,用户界面设计倾向于三者揉合在一起,MVC对它们进行了解耦,提高了灵活性与重用性。假如把view与controller结合在一起,结果就是model/view结构
model/view结构 • model与数据源通讯,并提供接口给结构中的别的组件使用。通讯的性质依赖于数据源的种类与model实现的方式。view从model获取model indexes,后者是数据项的引用。通过把model indexes提供给model,view可以从数据源中获取数据
model/view结构 • models,views,delegates之间通过信号,槽机制来进行通讯: • 从model发出的信号通知view数据源中的数据发生了改变。 • 从view发出的信号提供了有关被显示的数据项与用户交互的信息。 • 从delegate发生的信号被用于在编辑时通知model和view关于当前编辑器的状态信息。
Models • 所有的item models都基于QAbstractItemModel类,这个类定义了用于views和delegates访问数据的接口。此类是由QproxyModel、QAbstractListModel、 QAbstractTableModel、QAbstractProxyModel、QDirModel、QFileSystemModel、QHelpContentModel 和QStandardItemModel类继承。
Models • QT提供了一些现成的models用于处理数据 • QStringListModel 用于存储简单的QString列表。 • QStandardItemModel 管理复杂的树型结构数据项,每项都可以包含任意数据。 • QDirModel 提供本地文件系统中的文件与目录信息。 • QSqlQueryModel, QSqlTableModel,QSqlRelationTableModel用来访问数据库。
Views • 不同的view都完整实现了各自的功能:QListView把数据显示为一个列表,QTableView把Model 中的数据以table的形式表现,QTreeView 用具有层次结构的列表来显示model中的数据。这些类都基于QAbstractItemView抽象基类,尽管这些类都是现成的,完整的进行了实现,但它们都可以用于子类化以便满足定制需求。
Delegates • QAbstractItemDelegate 是model/view架构中的用于delegate的抽象基类。缺省的delegate实现在QItemDelegate类中提供。它可以用于Qt标准views的缺省 delegate .
标准Model • 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中都会被高亮。
model与views的搭配使用 • 先装配出一个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()));splitter->setWindowTitle("Two views onto the same directory model"); splitter->show(); return app.exec(); }
Model类 • 在model/view构架中,model为view和delegates使用数据提供了标准接口。在Qt中,标准接口QAbstractItemModel类中被定义。不管数据在底层以何种数据结构存储,QAabstractItemModel的子类会以层次结构的形式来表示数据,结构中包含了数据项表。我们按这种约定来访问model中的数据项,但这个约定不会对如何显示这些数据有任何限制。数据发生改变时,model通过信号槽机制来通知关联的views。
Model Indexes • 为了使数据存储与数据访问分开,引入了model index的概念。通过model index,可以引用model中的数据项,Views和delegates都使用indexes来访问数据项,然后再显示出来。因此,只有model需要了解如何获取数据,被model管理的数据类型可以非常广泛地被定义。Model indexes包含一个指向创建它们的model的指针,这会在配合多个model工作时避免混乱。QAbstractItemModel *model = index.model();
行与列 • 在最基本的形式中,一个model可作为一个简单的表来访问,每个数据项由行,列数来定位。这必不意味着底层的数据用数组结构来存储。行和列的使用仅仅是一种约定,它允许组件之间相互通讯。可以通过指定model中的行列数来获取任一项数据,可以得到与数据项一一对应的那个index。QModelIndex index = model->index(row, column, ...);
行与列 • 右图代表一个基本的table model,它的每一项用一对行列数来定位。通过行列数,可以获取代表一个数据项的model index . QModelIndex indexA = model->index(0, 0, QModelIndex()); QModelIndex indexB = model->index(1, 1, QModelIndex()); QModelIndex indexC = model->index(2, 1, QModelIndex());一个model的顶级项,由QModelIndex()取得,它们上式被用作父项
父项 • 类似于表的接口在搭配使用table或list view时理想的,这种行列系统与view显示的方式是确切匹配的。然则,像tree views这种结构需要model提供更为灵活的接口来访问数据项。每个数据项可能是别的项的父项,上级的项可以获取下级项的列表。当获取model中数据项的index时,我们必须指定关于数据项的父项的信息。在model外部,引用一个数据项的唯一方法就是通过model index,因此需要在求取model index时指定父项的信息。QModelIndex index = model->index(row, column, parent);
父项 • 右图中,A项和C项作为model中顶层的兄弟项:QModelIndex indexA = model->index(0, 0, QModelIndex()); QModelIndex indexC = model->index(2, 1, QModelIndex());A有许多孩子,它的一个孩子B用以下代码获取:QModelIndex indexB = model->index(1, 0, indexA);
View 类 • 在model/view架构中,view从model中获得数据项然后显示给用户。数据显示的方式不必与model提供的表示方式相同,可以与底层存储数据项的数据结构完全不同。内容与显式的分离是通过由QAbstractItemModel提供的标准模型接口,由QAsbstractItemview提供的标准视图接口共同实现的。普遍使用model index来表示数据项。view负责管理从model中读取的数据的外观布局。
使用现成的view • Qt提供了三个现成的view 类,它们能够以用户熟悉的方式显示model中的数据。QListView把model中的数据项以一个简单的列表的形式显示,或是以经典的图标视图的形式显示。QTreeView把model中的数据项作为具有层次结构的列表的形式显示,它允许以紧凑的深度嵌套的结构进行显示。QTableView却是把model中的数据项以表格的形式展现,更像是一个电子表格应用程序的外观布局。
使用model • 以前的例子中创建过一个string list model,可以给它设置一些数据,再创建一个view把model中的内容展示出来:int main(int argc, char *argv[]) { QApplication app(argc, argv); // Unindented for quoting purposes: QStringList numbers; numbers << "One" << "Two" << "Three" << "Four" << "Five"; QAbstractItemModel *model = new StringListModel(numbers); //要注意的是,这里把StringListModel作为一个QAbstractItemModel来使用 //。这样我们就可以使用model中的抽象接口,而且如果将来我们用别的//model代替了当前这个model,这些代码也会照样工作。//QListView提供的列表视图足以满足当前这个model的需要了。QListView *view = new QListView; view->setModel(model); view->show(); return app.exec();}
使用model view会渲染model中的内容,通过model的接口来访问它的数据。当用户试图编辑数据项时,view会使用缺省的delegate来提供一个编辑构件。