Qt Model View 框架
Model-View及Qt实现
Model-View-Controller架构最早出现在SmallTalk语言中,至今出现了很多变体。
Model是负责维护数据(如管理数据库),View负责显示与用户交互(如各种界面),Controller将控制业务逻辑。这种分层的做法在大型程序中使得数据、逻辑与界面分离,便于维护更新。
Qt引入了与MVC架构相似的模式Model-View架构,并加入了代理(delegate),用于自定义数据的编辑和渲染。
因为架构中的Model以表格的抽象方式访问数据,事实上并非Model-View的最佳选择。
Qt中Model,View,Delegate均由抽象类定义,并通过信号槽进行交互:
Model的信号通知View数据发生了改变
View的信号通知用户交互事件
Delegate的信号在编辑数据时用于通知Model和View的状态
QAbstractItemModel是所有Model的基类,它定义了View和Delegate访问数据的接口。
模型并不存储数据,而是通过与数据源交互得到数据。数据源包括数据库,文件,内存中的对象以及IO设备。
Qt 内置了许多标准模型:
QStringListModel:存储简单的字符串列表。
QStandardItemModel:可以用于树结构的存储,提供了层次数据。
QFileSystemModel:本地系统的文件和目录信息。
QSqlQueryModel、QSqlTableModel和QSqlRelationalTableModel:存取数据库数据。
如果这些标准模型不能满足需要,可以继承QAbstractItemModel创建新的Model。
QAbstractListModel或QAbstractTableModel提供了一些基本的实现,继承它们可能是更好的选择。
QAbstractItemView是所有View的基类。Qt 还提供了一系列标准的视图:QListView用于显示列表,QTableView用于显示表格,QTreeView用于显示层次数据,它们与List,Table, Tree这些布局在一定程度上对应。
QAbstractItemDelegate则是所有委托的抽象基类。自 Qt 4.4 之后,默认的委托实现是QStyledItemDelegate。但是,QStyledItemDelegate和QItemDelegate都可以作为视图的编辑器,二者的区别在于,QStyledItemDelegate使用当前样式进行绘制。在实现自定义委托时,推荐使用QStyledItemDelegate作为基类,或者结合 Qt style sheets。
QListWidget,QtreeWidget,QTableWidget
基于MVC架构,Qt提供了QListWidget,QtreeWidget,QTableWidget三个可视化组件,它们均继承了相应的View类,集成了Model-View的功能,程序员可以方便地使用这些类进行开发标准的List、Tree和Table组件。
QListWidget
QListWidget用于显示列表,QListWidget的创建方法与其它Widget一样需要指定一个父组件QListWidget(QWidget * parent = 0)
。
QListWidget的列表项是QListWidgetItem对象,QListWidgetItem可以存储和显示图标及文本。
在建立QListWidgetItem 对象时指定一个QListWidget对象作为父对象即可将列表项添加到列表组件最后,调用 void addItem(QListWidgetItem * item)
实例方法也可以将列表项添加到列表尾。
void insertItem(int row, QListWidgetItem * item);
系列重载函数可以将菜单项添加到指定的位置。
void insertItems(int row, const QStringList & labels)
与void addItems(const QStringList & labels)
方法则可以批量添加列表项。
QListWidgetItem可以在创建对象的时候指定图标和文本。
QListWidgetItem(const QIcon & icon, const QString & text, QListWidget * parent = 0, int type = Type)
,也可以通过setIcon(const QIcon & icon)
和setText(const QString & text)
设置。
对于Item的显示风格有很多选择,详情可以查阅Qt文档。
QListWidget继承了QListView的setViewMode函数可以设置列表的显示风格。QListWidget定义了一系列信号,它们会在列表项被点击等事件发生时发出。
QTreeWidget
QTreeWidget用于显示树状组件,其用法与QListWidget非常相似,它的项是QTreeWidgetItem对象。
QTreeWidgetItem有非常多的重载构造函数,QTreeWidgetItem可以接受QTreeWidget或QTreeWidget作为父对象,由此可以创建树状结构。
QTreeWidget和QTreeWidgetItem中常使用QList来创建多根树。
QTreeWidget可以用来显示类似Windows资源管理器的界面。
void setColumnCount(int columns)
可以设置列数目,而QTreeWidget的使用QStringList存储文本也是为了存储多列数据。
void setHeaderLabels(const QStringList & labels)
可以设定列名称。
QTableWidgets
QTableWidget的用法与前两个相似,其项目类为QTableWidgetItem。初始化QTableWidget对象时需要先指定对象的宽和高,使用void setItem(int row, int column, QTableWidgetItem * item)
将项目添加到指定单元格
Model
标准Model
QStringListModel
QStringListModel是最简单的模型类,具备向视图提供字符串数据的能力。QStringListModel是一个可编辑的模型,可以为组件提供一系列字符串作为数据,可以将其看作是封装了QStringList的模型。
QStringListModel很多时候都会作为QListView或者QComboBox这种只有一列的视图组件的数据模型。
void setStringList(const QStringList & strings);
用于设置QStringListModel所维护的StringList,使用View的void setModel(QAbstractItemModel * model)
函数将View与Model关联。
QFileSystemModel
QFileSystemModel的作用是维护一个目录的信息。因此,它不需要保存数据本身,而是保存这些在本地文件系统中的实际数据的一个索引。我们可以利用QFileSystemModel访问文件系统信息、甚至通过模型来修改文件系统。QTreeView是最适合应用QFileSystemModel的视图。
model = new QFileSystemModel;
model->setRootPath(QDir::currentPath());
treeView = new QTreeView(this);
treeView->setModel(model);
treeView->setRootIndex(model->index(QDir::currentPath()));
自定义Model
QAbstractItemModel定义了Model的标准接口。QAbstractItemModel及其派生类均以表格的形式提供访问数据。
自定义Model需要继承QAbstractItemModel并重写下列函数:
data()
QVariant QAbstractItemModel::data(const QModelIndex & index,
int role = Qt::DisplayRole) const
访问数据的接口,QModelIndex是存储Model表格的索引,index.row()
和index.column()
可以得到索引中指向的行或列。
role是一个枚举代表了数据的渲染方式,QVariant是变体型可以被转换为任意Qt兼容的数据类型。
setData()
bool QAbstractItemModel::setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole)
写入数据的接口。
dataChanged信号
void QAbstractItemModel::dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QVector & roles = QVector ())
在数据被改变后由setData()方法发送dataChanged()信号,通知视图刷新数据。使用两个QModelIndex通知刷新的范围。
此外还有一些工具函数:
- rowCount() / columnCount()
返回模型的行数 / 列数。
- headerData()
返回表头信息。
示例:
显示汇率表的应用,底层的数据使用一个QMap<QString, double>
类型的数据,作为key的QString是货币名字,作为value的double是这种货币对美元的汇率
CurrencyModel.h
class CurrencyModel : public QAbstractTableModel
{
Q_OBJECT
public:
CurrencyModel(QObject *parent = 0);
void setCurrencyMap(const QMap<QString, double> &map);
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
QString currencyAt(int offset) const;
QMap<QString, double> currencyMap;
};
CurrencyModel.cpp
CurrencyModel::CurrencyModel(QObject *parent)
: QAbstractTableModel(parent)
{
}
int CurrencyModel::rowCount(const QModelIndex & parent) const
{
return currencyMap.count();
}
int CurrencyModel::columnCount(const QModelIndex & parent) const
{
return currencyMap.count();
}
QVariant CurrencyModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role == Qt::TextAlignmentRole) {
return int(Qt::AlignRight | Qt::AlignVCenter);
}
else if (role == Qt::DisplayRole) {
QString rowCurrency = currencyAt(index.row());
QString columnCurrency = currencyAt(index.column());
if (currencyMap.value(rowCurrency) == 0.0)
return "####";
double amount = currencyMap.value(columnCurrency) / currencyMap.value(rowCurrency);
return QString("%1").arg(amount, 0, 'f', 4);
}
return QVariant();
}
bool CityModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || role != Qt::EditRole) {
return false;
}
if ( currencyAt(index.column()) == "USD") {
QString currency = currencyAt(index.row());
currencyMap[currency] = toInt(value);
QModelIndex columnIndexBegin = createIndex(index.column(),0);
QModelIndex columnIndexEnd = createIndex(index.column(),currencyMap.count()- 1);
emit dataChanged(columnIndexBegin, columnIndexEnd);
QModelIndex rawIndexBegin = createIndex(0,index.raw());
QModelIndex rawIndexEnd = createIndex(currencyMap.count()- 1,index.raw());
emit dataChanged(rawIndexBegin, rawIndexEnd);
return true;
}
return false;
}
QVariant CurrencyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
return currencyAt(section);
}
void CurrencyModel::setCurrencyMap(const QMap<QString, double> &map)
{
currencyMap = map;
reset();
}
QString CurrencyModel::currencyAt(int offset) const
{
return (currencyMap.begin() + offset).key();
}
Qt Model View 框架的更多相关文章
- qt model/view 架构基础介绍之QListWidget
# -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' from PyQt4.QtGui import * from Py ...
- Qt Model/View(官方翻译,图文并茂)
http://doc.trolltech.com/main-snapshot/model-view-programming.html 介绍 Qt 4推出了一组新的item view类,它们使用mode ...
- (转)Qt Model/View 学习笔记 (七)——Delegate类
Qt Model/View 学习笔记 (七) Delegate 类 概念 与MVC模式不同,model/view结构没有用于与用户交互的完全独立的组件.一般来讲, view负责把数据展示 给用户,也 ...
- (转)Qt Model/View 学习笔记 (五)——View 类
Qt Model/View 学习笔记 (五) View 类 概念 在model/view架构中,view从model中获得数据项然后显示给用户.数据显示的方式不必与model提供的表示方式相同,可以与 ...
- (转)Qt Model/View 学习笔记 (二)——Qt Model/View模式举例
Qt Model/View模式举例 Qt提供了两个标准的models:QStandardItemModel和QDirModel.QStandardItemModel是一个多用途的model,可用于表示 ...
- (转)Qt Model/View 学习笔记 (一)——Qt Model/View模式简介
Qt Model/View模式简介 Qt 4推出了一组新的item view类,它们使用model/view结构来管理数据与表示层的关系.这种结构带来的 功能上的分离给了开发人员更大的弹性来定制数据项 ...
- (一) Qt Model/View 的简单说明
(一) Qt Model/View 的简单说明 .预定义模型 (二)使用预定义模型 QstringListModel例子 (三)使用预定义模型QDirModel的例子 (四)Qt实现自定义模型基于QA ...
- qt model/view/delegate
Qt Model/View理解(一)---构造model https://blog.csdn.net/weixin_42303052/article/details/89233887 Qt Model ...
- Qt Model/View 的简单说明
目录: (一) Qt Model/View 的简单说明 .预定义模型 (二)使用预定义模型 QstringListModel例子 (三)使用预定义模型QDirModel的例子 (四)Qt实现自定义模型 ...
随机推荐
- 使用Linq对Hashtable和Dictionary<T,T>查询的效率比较
近期做版本迭代任务,有一个在店铺头部展示店主所在的城市名称和省份名称的需求,店主信息表中保存了店主所在的城市Id和省份Id,由于原有业务复杂,要尽量减少Sql执行时间,所以不考虑join城市地区详细表 ...
- Feed back TFS 2017 RC upgrade status to product team in product group 2017.03.01
作为微软的MVP,有一个我最喜欢的好处,就是可以与产品组(产品研发部门)有零距离接触,可以最先拿到即将发版的产品,并且和产品组沟通,对产品中出现的问题实时反馈. 看到TFS产品组吸收了自己的建议和反馈 ...
- Elasticsearch 核心插件Kibana 本地文件包含漏洞分析(CVE-2018-17246)
不久前Elasticsearch发布了最新安全公告, Elasticsearch Kibana 6.4.3之前版本和5.6.13之前版本中的Console插件存在严重的本地文件包含漏洞可导致拒绝服务攻 ...
- 基于Easyui框架的datagrid绑定数据,新增,修改,删除方法(四)
@{ ViewBag.Title = "xxlist"; } <script type="text/javascript" language=" ...
- ORM到底是什么有何优缺点
转载地址:http://www.cnblogs.com/wgbs25673578/p/5140482.html ORM的概念, ORM到底是什么 一.ORM简介 对象关系映射(Obje ...
- 【cocos2d-x 仙凡奇缘-网游研发(2) 角色换线系统】
转载请注明出处:http://www.cnblogs.com/zisou/p/xianfan01.html 做一款游戏就先得制作好策划文档,和基本的人物世界构架的设计,然后架空在这样一个虚拟的世界中每 ...
- 程序媛计划——mysql修改表结构
#查看表的结构 mysql> desc score; +------------+--------------+------+-----+---------+----------------+ ...
- AVL树的实现——c++
一.概念 AVL树是根据它的发明者G.M. Adelson-Velsky和E.M. Landis命名的.它是最先发明的自平衡二叉查找树,也被称为高度平衡树.相比于"二叉查找树",它 ...
- poj3070 Fibonacci(矩阵快速幂)
矩阵快速幂基本应用. 对于矩阵乘法与递推式之间的关系: 如:在斐波那契数列之中 f[i] = 1*f[i-1]+1*f[i-2] f[i-1] = 1*f[i-1] + 0*f[i-2].即 所以, ...
- Python任意网段Web端口信息探测工具
此篇关于多线程工具的文章,非常适合新手学习,工具效率也挺高的,代码也比较完善,如题. 本文作者:i春秋签约作家——Aedoo 0×00 前言 笔者前一段时间发布了原创文章,“[Python黑客] Py ...