本文将介绍自定义Model过程中数据库数据源的获取方法,我使用过以下三种方式获取数据库数据源:
  • 创建 存储对应数据库所有字段的 结构体,将结构体置于容器中返回,然后根据索引值(QModelIndex)取出最终的字段值;
  • 创建 存储对应数据库所有字段的 类,将类对象置于容器中返回,然后利用内省机制获取对象相应字段(属性)值。
  • 不用自己造轮子,直接使用QVariantList类,将QVariantList 对象置于容器中,如QVector<QVariantList >,然后根据索引值(QModelIndex)取出最终的字段值;
本文重点介绍第二种,即利用QT的内省机制来获取数据。
 
1.自定义Model过程(通过内省功能获得字段值,也就是第二种方法)
本文中自定义Model继承于QAbstractTableModel ,重点描述setData(..)函数与data(...)函数的重载过程。
 
 
首先需要介绍 Parameter类,该类用于存储查询数据库中某表所得的字段值。
 //Parameter.h
//加粗单词为成员变量
//假设数据库中某表有三个字段Index,Name,Describe class Parameter : public QObject
{
Q_OBJECT
public:
explicit Parameter( QObject *parent = ); Q_INVOKABLE QVariant getIndex() const { return index;} //用Q_INVOKABLE声明后才能被元对象(QMetaObject)调用
Q_INVOKABLE void setIndex(const QVariant &value) { index = value.toInt(); } Q_INVOKABLE QVariant getName() const { return name; }
Q_INVOKABLE void setName(const QVariant &value) { name = value.toString(); } Q_INVOKABLE QVariant getDecribe() const { return describe; }
Q_INVOKABLE QVariant setDescribe(const QVariant &value) { describe = value; } QMap<int, int> getMethodGETIndexs()const;//获得“取值器”函数(即getXX函数) 的索引值列表,这些函数都被Q_INVOKABLE声明过
QMap<int, int> getMethodSETIndexs() const;//获得“设置器”函数(即setXX函数) 的索引值列表,这些函数都被Q_INVOKABLE声明过 private:
void setMethodGETIndexs(); //设置“取值器”函数(即getXX函数) 的索引值列表,这些函数都被Q_INVOKABLE声明过
void setMethodSETIndexs(); //设置“设置器”函数(即setXX函数) 的索引值列表,这些函数都被Q_INVOKABLE声明过 static int getNewIndex(); int index;
QString name;
QString describe; QMap<int,int> methodGETIndexs;
QMap<int,int> methodSETIndexs;
};
 //Parameter.cpp

 Parameter::Parameter(QObject *parent) :
QObject(parent),
index(getNewIndex()),
name("Unnamed"),
describe("")
{
setMethodGETIndexs();
setMethodSETIndexs();
} void Parameter::setMethodGETIndex()
{
int index1 = this->metaObject()->indexOfMethod("getIndex()");
methodGETIndexs.insert(,index1); int index2 = this->metaObject()->indexOfMethod("getName()");
methodGETIndexs.insert(,index2); int index3 = this->metaObject()->indexOfMethod("getDecribe()");
methodGETIndexs.insert(,index3); } void Parameter::setMethodSETIndexs()
{
int index1 = this->metaObject()->indexOfMethod("setIndex(QVariant)");
methodSETIndexs.insert(,index1); int index2 = this->metaObject()->indexOfMethod("setName(QVariant)");
methodSETIndexs.insert(,index2); int index3 = this->metaObject()->indexOfMethod("setDescribe(QVariant)");
methodSETIndexs.insert(,index3);
} QMap<int, int> Parameter::getMethodSETIndexs() const
{
return methodSETIndexs;
} QMap<int, int> Parameter::getMethodGETIndexs() const
{
return methodGETIndexs;
} int Parameter::getNewIndex()
{
//查询数据库
//返回最新的Index字段
}
Parameter类声明了对应数据库表中字段(field)的成员变量,并分别为这些成员变量编写了setxx()函数和getxx()函数,并对这些函数进行Q_INVOKABLE声明
然后,在setMethodGETIndexs()函数 与 setMethodSETIndexs()函数中,使用QMetaObject::indexOfMethod(...)函数获取每个函数在QMetaObject对象中的索引值,将该按顺序索引值存入到容器中,其插入顺序与TableModel中的字段顺序一致。
最后,在TableModel中调用Parameter类的getMethodSETIndexs()函数与getMethodGETIndexs()函数获得索引值列表。
 
 //TableModel.h
class TableModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit TableModel(QObject *parent = );
int rowCount(const QModelIndex &parent = QModelIndex()) const;//
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
private:
static QList<Parameter*> getTableParameters(); //该函数用于初始化dataParameters QVariant specificIndexValue(const QModelIndex &index) const;
int getMethodGETIndex(const QModelIndex &index) const;
QMetaMethod getMetaMethod(const QModelIndex &index,int methodIndex) const;
bool setSpecificData(const QModelIndex &index, const QVariant &value);
int getMethodSETIndex(const QModelIndex &index); QList<Parameter*> dataParameters; //存储从数据库表中查询所得的值,每个Parameter对象代表一条记录
//tablemodel.cpp

TableModel::TableModel(QObject *parent) :
QAbstractTableModel(parent),
dataParameters(getTableParameters())
{ } static TableModel::QList<Parameter*> getTableParameters()
{
//查询数据库,返回字段值列表
} int TableModel::rowCount(const QModelIndex &parent = QModelIndex())
{
dataParameters.size();
} int TableModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return dataParameters.getMethodGETIndexs().size();
} QVariant TableModel::data(const QModelIndex &index, int role) const
{
if(!index.isValid()){
return QVariant();
}
return specificData(index,role);
} QVariant TableModel::specificData(const QModelIndex &index, int role)const
{
switch(role)
{
case Qt::TextAlignmentRole:
return int(Qt::AlignHCenter | Qt::AlignVCenter);
case Qt::DisplayRole:
return specificIndexValue(index);
case Qt::EditRole:
return specificIndexValue(index);
default:
return QVariant();
}
return QVariant();
} QVariant TableModel::specificIndexValue(const QModelIndex &index) const
{
QVariant retValue;
int methodIndex = methodGETIndex(index);
QMetaMethod getMethod = getMetaMethod(index,methodIndex);
getMethod.invoke(dataParameters.at(index.row()),Qt::DirectConnection,Q_RETURN_ARG(QVariant,retValue));
return retValue;
} int TableModel::getMethodGETIndex(const QModelIndex &index) const
{
int methodIndex = dataParameters.at(index.row())->getMethodGETIndexs().value(index.column());
return methodIndex;
} QMetaMethod TableModel::getMetaMethod(const QModelIndex &index,int methodIndex) const
{
QMetaMethod method = dataParameters.at(index.row())->metaObject()->method(methodIndex);
return method;
} bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if(!isIndexValid(index))
return false;
if(role == Qt::EditRole && setSpecificData(index,value))
ResParameters::instance().modifyRecord(index); return QAbstractTableModel::setData(index,value);
} bool TableModel::setSpecificData(const QModelIndex &index,
const QVariant &value)
{
if( specificIndexValue(index) != value){ int methodIndex = getMethodSETIndex(index);
QMetaMethod setMethod = getMetaMethod( index, methodIndex);
return setMethod.invoke( dataParameters.at(index.row()), Qt::DirectConnection, Q_ARG(QVariant,value) ); }
return false;
} int TableModel::getMethodSETIndex(const QModelIndex &index)
{
int methodIndex = dataParameters.at(index.row())->getMethodSETIndexs().value(index.column());
return methodIndex;
}
成员变量 QList<Parameter*> dataParameters中存储了数据库表中的字段值,且每个Parameter对象代表一条记录。
 
我们知道,TableModel数据的显示与rowCount()、columnCount()、data()函数息息相关,我们重载了这三个函数。
为了让model的行和列与dataParameters一一对应:
令rowCount()函数返回dataParameters的条目数(行数目);
令columnCount()返回dataParameters中每条记录的字段数目(列数目)。
对于Variant data(const QModelIndex &index, int role) const函数,在选定的role下,调用specificIndexValue(const QModelIndex &index)函数,根据索引值获得行号和列号,先根据行号确定容器中某一个Parameter对象(即某一条记录),然后再根据列号,获得该Parameter对象中支持 元对象调用的 函数的索引值(如getMethodGETIndex()函数所示),获取函数索引值后,如getMetaMethod()所示,可获得QMetaMethod对象,然后调用invoke()函数,赋予合适的参数值,就等价于调用当前函数索引值对应的那个函数。
这样做的好处在于,可直接通过行号与列号进行寻址,避免了条件判断语句,使代码大大提高了简洁性与复用性。
setData()函数与data()函数类似,不再详述。
 
总结:利用内省机制获得对象的成员函数,并调用之,能够避免复杂的条件判断逻辑,能够提高复用性。但是,在这里没有提及的有性能问题,我没有研究对性能会有什么影响,当然,简单的PC软件是基本看不到影响的,其次,利用Parameter类存储数据库表字段值,使Parameter只能用于同一个表,那么每个返回数据库字段值的函数也就只能服务于同一个表,这样也会有很多重复代码产生。所以接下来,我将进一步改进,放弃利用自定义类而使用QVariantList类来存储数据库表的每一条记录。

最新文章

  1. $stateParams
  2. BootStrap的一个标准框架的内容解释——来源于bootstrap官网
  3. swift UIImage加载远程图片和圆角矩形
  4. es6+移动轮播插件
  5. python和numpy的版本、安装位置
  6. ggplot2 上篇
  7. 如何去掉WinForm或者WPF的最大化和最小化按钮
  8. IOS7官方推荐图标和图像尺寸
  9. Android--Service之绑定服务交互
  10. PCB的整个加工流程
  11. asp.net 一般处理程序session 为 null
  12. Sublime themes/ lint themes setup
  13. 萝卜德森的sublime笔记中文翻译版
  14. 深入解析java String中getBytes()的编码问题
  15. 颜色空间之CIE2000色差公式
  16. 学习HttpClient,从两个小例子开始
  17. 《CSS世界》读书笔记(八)
  18. NET Core微服务之路:自己动手实现Rpc服务框架,基于DotEasy.Rpc服务框架的介绍和集成
  19. Core Animation-2:寄宿图
  20. [UE4]UMG和关卡坐标变换、旋转小地图

热门文章

  1. 构建一个基本的前端自动化开发环境 —— 基于 Gulp 的前端集成解决方案(四)
  2. Xshell 连接CentOS服务器解密
  3. C++随笔:.NET CoreCLR之GC探索(3)
  4. [原]Redis主从复制各种环境下测试
  5. 在Visual Studio Code中配置GO开发环境
  6. pt-heartbeat
  7. RabbitMQ + PHP (一)入门与安装
  8. webpack学习总结
  9. Android中开发工具Android Studio修改created用户(windows环境)
  10. Android local.properties 文件读取