分享Qt Model View 学习总结笔记Word格式.docx
《分享Qt Model View 学习总结笔记Word格式.docx》由会员分享,可在线阅读,更多相关《分享Qt Model View 学习总结笔记Word格式.docx(24页珍藏版)》请在冰豆网上搜索。
![分享Qt Model View 学习总结笔记Word格式.docx](https://file1.bdocx.com/fileroot1/2023-1/7/f786e81a-4d74-4646-aaca-7e45e27da15e/f786e81a-4d74-4646-aaca-7e45e27da15e1.gif)
models,views,delegates之间通过信号,槽机制来进行通讯:
从model发出的信号通知view数据源中的数据发生了改变。
从view发出的信号提供了有关被显示的数据项与用户交互的信息。
从delegate发生的信号被用于在编辑时通知model和view关于当前编辑器的状态信息。
Models
所有的itemmodels都基于QAbstractItemModel类,这个类定义了用于views和delegates访问数据的接口。
数据本身不必存储在model,数据可被置于一个数据结构或另外的类,文件,数据库,或别的程序组件中。
关于model的基本概念在ModelClasses部分中描述。
QAbstractItemModel提供给数据一个接口,它非常灵活,基本满足views的需要,无论数据用以下任何样的形式表现,如tables,lists,trees。
然而,当你重新实现一个model时,如果它基于table或list形式的数据结构,最好从QAbstractListModel,QAbstractTableModel开始做起,因为它们提供了适当的常规功能的缺省实现。
这些类可以被子类化以支持特殊的定制需求。
子类化model的过程在CreateNewModel部分讨论
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没有提供需要的接口或是你想用listview表示数据,可以用一个代理
model在用view表示数据之前对你的model数据结构进行转换。
便利类
许多便利类都源于标准的view类,它们方便了那些使用Qt中基于项的view与table类,它们不应该被子类化,
它们只是为Qt3的等价类提供一个熟悉的接口。
这些类有QListWidget,QTreeWidget,QTableWidget,它们提供了如Qt3中的QListBox,QlistView,QTable相似的行为。
这些类比View类缺少灵活性,不能用于任意的models,推介使用model/view的方法处理数据。
QtModel/View学习笔记
(二)
介绍
Qt提供了两个标准的models:
QStandardItemModel和QDirModel。
QStandardItemModel是一个多用途的model,可用于表示list,table,treeviews所需要的各种不同的数据结构。
这个model也持有数据。
QDirModel维护相关的目录内容的信息,它本身不持有数据,仅是对本地文件系统中的文件与目录的描述。
QDirModel是一个现成的model,很容易进行配置以用于现存的数据,使用这个model,可以很好地展示如何给一个现成的view设定model,研究如何用modelindexes来操纵数据。
model与views的搭配使用
QListView与QTreeView很适合与QDirModel搭配。
下面的例子在treeview与listview显示了相同的信息,QDirModel提供了目录内容数据。
这两个Views共享用户选择,因此每个被选择的项在每个view中都会被高亮。
先装配出一个QDirModel以供使用,再创建views去显示目录的内容。
这给我展示了使用model的最简单的方式。
model的创建与使用都在main()函数中完成:
intmain(intargc,char*argv[])
{
QApplicationapp(argc,argv);
QSplitter*splitter=newQSplitter;
QDirModel*model=newQDirModel;
//从缺省目录创建数据
QTreeView*tree=newQTreeView(splitter);
tree->
setModel(model);
setRootIndex(model->
index(QDir:
currentPath()));
QListView*list=newQListView(splitter);
list->
//配置一个view去显示model中的数据,只需要简单地调用setModel(),并把目录model作为参数传递
//setRootIndex()告诉views显示哪个目录的信息,这需要提供一个modelindex,然后用这个
//modelindex去model中去获取数据
//index()这个函数是QDirModel特有的,通过把一个目录做为参数,得到了需要的modelindex
//其他的代码只是窗口show出来,进入程序的事件循环就好了
splitter->
setWindowTitle("
Twoviewsontothesamedirectorymodel"
);
show();
returnapp.exec();
}
QtModel/View学习笔记(三)
Model类
基本概念
在model/view构架中,model为view和delegates使用数据提供了标准接口。
在Qt中,标准接口QAbstractItemModel类中被定义。
不管数据在底层以何种数据结构存储,QAabstractItemModel的子类会以层次结构的形式来表示数据,结构中包含了数据项表。
我们按这种约定来访问model中的数据项,但这个约定不会对如何显示这些数据有任何限制。
数据发生改变时,model通过信号槽机制来通知关联的views。
ModelIndexes
为了使数据存储与数据访问分开,引入了modelindex的概念。
通过modelindex,可以引用model中的数据项,Views和delegates都使用indexes来访问数据项,然后再显示出来。
因此,只有model需要了解如何获取数据,被model管理的数据类型可以非常广泛地被定义。
Modelindexes包含一个指向创建它们的model的指针,这会在配合多个model工作时避免混乱。
QAbstractItemModel*model=index.model();
modelindexes提供了对一项数据信息的临时引用,通过它可以访问或是修改model中的数据。
既然model有时会重新组织内部的数据结构,这时modelindexes便会失效,因此不应该保存临时的modelindexes。
假如需要一个对数据信息的长期的引用,那么应该创建一个persistentmodelindex。
这个引用会保持更新。
临时的modelindexes由QModelIndex提供,而具有持久能力的modelindexes则由QPersistentModelIndex提供。
在获取对应一个数据项的modelindex时,需要考虑有关于model的三个属性:
行数,列数,父项的modelindex。
行与列
在最基本的形式中,一个model可作为一个简单的表来访问,每个数据项由行,列数来定位。
这必不意味着底层的数据用数组结构来存储。
行和列的使用仅仅是一种约定,它允许组件之间相互通讯。
可以通过指定model中的行列数来获取任一项数据,可以得到与数据项一一对应的那个index。
QModelIndexindex=model->
index(row,column,...);
Model为简单的,单级的数据结构如list与tables提供了接口,它们如上面代码所显示的那样,不再需要别的信息被提供。
当我们在获取一个modelindex时,我们需要提供另外的信息。
上图代表一个基本的tablemodel,它的每一项用一对行列数来定位。
通过行列数,可以获取代表一个数据项的modelindex.
QModelIndexindexA=model->
index(0,0,QModelIndex());
QModelIndexindexB=model->
index(1,1,QModelIndex());
QModelIndexindexC=model->
index(2,1,QModelIndex());
一个model的顶级项,由QModelIndex()取得,它们上式被用作父项。
父项
类似于表的接口在搭配使用table或listview时理想的,这种行列系统与view显示的方式是确切匹配的。
然则,像treeviews这种结构需要model提供更为灵活的接口来访问数据项。
每个数据项可能是别的项的父项,上级的项可以获取下级项的列表。
当获取model中数据项的index时,我们必须指定关于数据项的父项的信息。
在model外部,引用一个数据项的唯一方法就是通过modelindex,因此需要在求取modelindex时指定父项的信息。
index(row,column,parent);
上图中,A项和C项作为model中顶层的兄弟项:
QModelIndexindexA=model->
A有许多孩子,它的一个孩子B用以下代码获取:
QModelIndexindexB=model->
index(1,0,indexA);
项角色
model中的项可以作为各种角色来使用,这允许为不同的环境提供不同的数据。
举例来说,Qt:
DisplayRole被用于访问一个字符串,它作为文本会在view中显示。
典型地,每个数据项都可以为许多不同的角色提供数据,标准的角色在Qt:
ItemDataRole中定义。
我们可以通过指定modelindex与角色来获取我们需要的数据:
QVariantvalue=model->
data(index,role);
角色指出了从model中引用哪种类型的数据。
views可以用不同的形式显示角色,因此为每个角色提供正确的信息是非常重要的。
通过为每个角色提供适当数据,model也为views和delegates提供了暗示,如何正确地把这些数据项显给用户。
不同的views可以自由地解析或忽略这些数据信息,对于特殊的场合,也可以定义一些附加的角色。
概念总结:
1,Modelindexes为views与delegages提供model中数据项定位的信息,它与底层的数据结构无关。
2,通过指定行,列数,父项的modelindex来引用数据项。
3,依照别的组件的要求,modelindexes被model构建。
4,使用index()时,如果指定了有效的父项的modelindex,那么返回得到的modelindex对应于父项的某个孩子。
5,使用index()时,如果指定了无效的父项的modelindex,那么返回得到的modelindex对应于顶层项的某个孩子。
6,角色对一个数据项包含的不同类型的数据给出了区分。
使用ModelIndexes
QModelIndexparentIndex=model->
currentPath());
intnumRows=model->
rowCount(parentIndex);
for(introw=0;
row<
numRows;
++row)
QModelIndexindex=model->
index(row,0,parentIndex);
tringtext=model->
data(index,Qt:
DisplayRole).toString();
//Displaythetextinawidget.
以上的例子说明了从model中获取数据的基本原则:
1,model的尺寸可以从rowCount()与columnCount()中得出。
这些函数通常都需要一个表示父项的modelindex。
2,modelindexes用来从model中访问数据项,数据项用行,列,父项modelindex定位。
3,为了访问model顶层项,可以使用QModelIndex()指定。
4,数据项为不同的角色提供不同的数据。
为了获取数据,除了modelindex之外,还要指定角色。
QtModel/View学习笔记(四)
创建新的Models
model/view组件之间功能的分离,允许创建model利用现成的views。
这也可以使用标准的功能图形用户接口组件像QListView,QTableView和QTreeView来显示来自各种数据源的数据为。
QAbstractListModel类提供了非常灵活的接口,允许数据源以层次结构的形式来管理信息,也允许以某种方式对数据进行插入、删除、修改和存储。
它也提供了对拖拽操作的支持。
QAbstractListModel与QAbstractTableModel为简单的非层次结构的数据提供了接口,对于比较简单的list和tablemodels来说,这是不错的一个开始点。
设计一个Model
当我们为存在的数据结构新建一个model时,首先要考虑的问题是应该选用哪种model来为这些数据提供接口。
假如数据结构可以用数据项的列表或表来表示,那么可以考虑子类化QAbstractListModel或QAbstractTableModel
既然这些类已经合理地对许多功能提供缺省实现。
然而,假如底层的数据结构只能表示成具有层次结构的树型结构,那么必须得子类化QAbstractItemModel。
无论底层的数据结构采取何种形式,在特定的model中实现标准的QAbstractItemModelAPI总是一个不错的主意,这使得可以使用更自然的方式对底层的数据结构进行访问。
这也使得用数据构建model更为容易,其他的model/view组件也可以使用标准的API与之进行交互。
一个只读model示例
这个示例实现了一个简单的,非层次结构的,只读的数据model,它基于QStringistModel类。
它有一个QStringList作为它内部的数据源,只实现了一些必要的接口。
为了简单化,它子类化了QAbstractListModel,这个基类提供了合理的缺省行为,对外提供了比AbstractItemModel更为简单的接口。
当我们实现一个model时,不要忘了AbstractItemModel本身不存储任何数据,它仅仅提供了给views访问数据的接口。
classStringListModel:
publicQAbstractListModel
Q_OBJECT
public:
StringListModel(constQStringList&
strings,QObject*parent=0)
:
QAbstractListModel(parent),stringList(strings){}
introwCount(constQModelIndex&
parent=QModelIndex())const;
QVariantdata(constQModelIndex&
index,introle)const;
QVariantheaderData(intsection,Qt:
Orientationorientation,
introle=Qt:
DisplayRole)const;
private:
QStringListstringList;
};
除了构造函数,我们仅需要实现两个函数:
rowCount()返回model中的行数,data()返回与特定modelindex对应的数据项。
具有良好行为的model也会实现headerData(),它返回tree和tableviews需要的,在标题中显示的数据。
因为这是一个非层次结构的model,我们不必考虑父子关系。
假如model具有层次结构,我们也应该实现index()与parent()函数。
Model的尺寸
我们认为model中的行数与stringlist中的string数目一致:
intStringListModel:
rowCount(constQModelIndex&
parent)const
returnstringList.count();
在缺省情况下,从QAbstractListModel派生的model只具有一列,因此不需要实现columnCount()。
Model标题与数据
QVariantStringListModel:
data(constQModelIndex&
index,introle)const
if(!
index.isValid())
returnQVariant();
if(index.row()>
=stringList.size())
if(role==Qt:
DisplayRole)
returnstringList.at(index.row());
else
QVariantStringListModel:
headerData(intsection,Qt:
introle)const
if(role!
=Qt:
if(orientation==Qt:
Horizontal)
returnQString("
Column%1"
).arg(section);
Row%1"
一个数据项可能有多个角色,根据角色的不同输出不同的数据。
上例中,model中的数据项只有一个角色,DisplayRole,然而我们也可以重用提供给DisplayRole的数据,作为别的角色使用,如我们可以作为ToolTipRole来用。
可编辑的model
上面我们演示了一个只读的model,它只用于向用户显示,对于许多程序来说,可编辑的listmodel可能更有用。
我们只需要给只读的model提供另外两个函数flags()与setData()的实现。
下列函数声明被添加到类