zoukankan      html  css  js  c++  java
  • QT内省机制、自定义Model、数据库

    本文将介绍自定义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() const
    39 {
    40   return methodSETIndexs;
    41 }
    42 
    43 QMap<int, int> Parameter::getMethodGETIndexs() const
    44 {
    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(); //该函数用于初始化dataParameters
    13 
    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 *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类来存储数据库表的每一条记录。
  • 相关阅读:
    微信小程序 添加卡券至微信卡券
    微信小程序 引入第三方字体
    小程序 生成条形码barcode.js
    Pycharm编辑器功能之自动导入模块
    Cannot open include file: 'libxml/xpath.h': No such file or directory
    怎么在32位windows系统上搭建爬虫框架scrapy?
    python2.7安装Twisted报Microsoft Visual C++9.0 required
    在windows下搭建爬虫框架,安装pywin32时出错?
    python如何通过pymongo连接到mongodb?
    python2.7.12自带pip吗?
  • 原文地址:https://www.cnblogs.com/sfy5848/p/6030493.html
Copyright © 2011-2022 走看看