本文将介绍自定义Model过程中数据库数据源的获取方法,我使用过以下三种方式获取数据库数据源:

  • 创建 存储对应数据库所有字段的 结构体,将结构体置于容器中返回,然后根据索引值(QModelIndex)取出最终的字段值;
  • 创建 存储对应数据库所有字段的 类,将类对象置于容器中返回,然后利用内省机制获取对象相应字段(属性)值。
  • 不用自己造轮子,直接使用QVariantList类,将QVariantList 对象置于容器中,如QVector<QVariantList >,然后根据索引值(QModelIndex)取出最终的字段值;

本文重点介绍第二种,即利用QT的内省机制来获取数据。

 

1.自定义Model过程(通过内省功能获得字段值,也就是第二种方法)

本文中自定义Model继承于QAbstractTableModel ,重点描述setData(..)函数与data(...)函数的重载过程。

 

 

首先需要介绍 Parameter类,该类用于存储查询数据库中某表所得的字段值。

1 //Parameter.h 2 //加粗单词为成员变量 3 //假设数据库中某表有三个字段Index,Name,Describe 4  5 class Parameter : public QObject 6 { 7     Q_OBJECT 8 public: 9     explicit Parameter( QObject *parent = 0);10 11     Q_INVOKABLE QVariant getIndex() const { return index;} //用Q_INVOKABLE声明后才能被元对象(QMetaObject)调用12     Q_INVOKABLE void setIndex(const QVariant &value) { index = value.toInt(); }13 14     Q_INVOKABLE QVariant getName() const { return name; }15     Q_INVOKABLE void setName(const QVariant &value) { name = value.toString(); }16 17     Q_INVOKABLE QVariant getDecribe() const { return describe; }18     Q_INVOKABLE QVariant setDescribe(const QVariant &value) { describe = value; }19 20     QMap<int, int> getMethodGETIndexs()const;//获得“取值器”函数(即getXX函数)  的索引值列表,这些函数都被Q_INVOKABLE声明过21     QMap<int, int> getMethodSETIndexs() const;//获得“设置器”函数(即setXX函数) 的索引值列表,这些函数都被Q_INVOKABLE声明过22 23 private:24     void setMethodGETIndexs(); //设置“取值器”函数(即getXX函数) 的索引值列表,这些函数都被Q_INVOKABLE声明过25     void setMethodSETIndexs(); //设置“设置器”函数(即setXX函数) 的索引值列表,这些函数都被Q_INVOKABLE声明过26 27     static int getNewIndex();28 29     int index;30     QString name;31     QString describe;32 33     QMap<int,int> methodGETIndexs;34     QMap<int,int> methodSETIndexs;35 };
 
  
 
  
 1 //Parameter.cpp 2  3 Parameter::Parameter(QObject *parent) : 4   QObject(parent), 5   index(getNewIndex()), 6   name("Unnamed"), 7   describe("") 8 { 9    setMethodGETIndexs();10    setMethodSETIndexs();   
11 }12 13 void Parameter::setMethodGETIndex()14 {15   int index1 = this->metaObject()->indexOfMethod("getIndex()");16   methodGETIndexs.insert(0,index1);17 18   int index2 = this->metaObject()->indexOfMethod("getName()");19   methodGETIndexs.insert(1,index2);20 21   int index3 = this->metaObject()->indexOfMethod("getDecribe()");22   methodGETIndexs.insert(2,index3);23 24 }25 26 void Parameter::setMethodSETIndexs()27 {28   int index1 = this->metaObject()->indexOfMethod("setIndex(QVariant)");29   methodSETIndexs.insert(0,index1);30 31   int index2 = this->metaObject()->indexOfMethod("setName(QVariant)");32   methodSETIndexs.insert(1,index2);33 34   int index3 = this->metaObject()->indexOfMethod("setDescribe(QVariant)");35   methodSETIndexs.insert(2,index3);36 }37 38 QMap<int, int> Parameter::getMethodSETIndexs() const39 {40   return methodSETIndexs;41 }42 43 QMap<int, int> Parameter::getMethodGETIndexs() const44 {45   return methodGETIndexs;46 }47 48 int Parameter::getNewIndex()49 {50      //查询数据库51      //返回最新的Index字段52 }
 
  
Parameter类声明了对应数据库表中字段(field)的成员变量,并分别为这些成员变量编写了setxx()函数和getxx()函数,并对这些函数进行Q_INVOKABLE声明
然后,在setMethodGETIndexs()函数 与 setMethodSETIndexs()函数中,使用QMetaObject::indexOfMethod(...)函数获取每个函数在QMetaObject对象中的索引值,将该按顺序索引值存入到容器中,其插入顺序与TableModel中的字段顺序一致。
最后,在TableModel中调用Parameter类的getMethodSETIndexs()函数与getMethodGETIndexs()函数获得索引值列表。
 
 
  
 1 //TableModel.h 2 class TableModel : public QAbstractTableModel 3 { 4     Q_OBJECT 5 public: 6     explicit TableModel(QObject *parent = 0); 7     int rowCount(const QModelIndex &parent = QModelIndex()) const;// 8     int columnCount(const QModelIndex &parent = QModelIndex()) const; 9     QVariant data(const QModelIndex &index, int role) const;10     bool setData(const QModelIndex &index, const QVariant &value, int role);11 private:12     static  QList<Parameter*> getTableParameters(); //该函数用于初始化dataParameters13 14     QVariant specificIndexValue(const QModelIndex &index) const;15     int getMethodGETIndex(const QModelIndex &index) const;16     QMetaMethod getMetaMethod(const QModelIndex &index,int methodIndex) const;17     bool setSpecificData(const QModelIndex &index, const QVariant &value);18     int getMethodSETIndex(const QModelIndex &index);19 20     QList<Parameter*> dataParameters; //存储从数据库表中查询所得的值,每个Parameter对象代表一条记录
 
  
 
 
  
//tablemodel.cpp

TableModel::TableModel(QObject * TableModel::QList<Parameter*> TableModel::rowCount( QModelIndex &parent = TableModel::columnCount( QModelIndex &parent)  QModelIndex &index,  role) (! QModelIndex &index,  role) (Qt::AlignHCenter | QModelIndex &index)  methodIndex == TableModel::getMethodGETIndex( QModelIndex &index)  methodIndex = dataParameters.at(index.row())-> QModelIndex &index, methodIndex) = dataParameters.at(index.row())->metaObject()-> TableModel::setData( QModelIndex &index,  QVariant &value, (! (role == Qt::EditRole && TableModel::setSpecificData( QModelIndex & QVariant &( specificIndexValue(index) != methodIndex ==  TableModel::getMethodSETIndex( QModelIndex & methodIndex = dataParameters.at(index.row())->


成员变量 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类来存储数据库表的每一条记


https://blog.51cto.com/11496263/1882504