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类来存储数据库表的每一条记录。

时间: 2024-10-10 07:29:24

QT内省机制、自定义Model、数据库的相关文章

Qt核心机制与原理

转:  https://blog.csdn.net/light_in_dark/article/details/64125085 ★了解Qt和C++的关系 ★掌握Qt的信号/槽机制的原理和使用方法 ★了解Qt的元对象系统 ★掌握Qt的架构 ★理解Qt的事件模型,掌握其使用的时机 信号与槽.元对象系统.事件模型是Qt机制的核心,如果您想要掌握Qt编程,就需要对它们有比较深入的了解.本章重点介绍了信号与槽的基本概念和用法.元对象系统.Qt的事件模型,以及它们在实际使用过程中应注意的一些问题. Qt对

QT——模型/视图(model/view)

数据项中引入模型/视图架构,可以方便的将数据与表现层分开. ------------------------------------- 模型Model:一般来说,Model里面并不真正存储数据(数据少的话也可以直接存储在Model里),只是负责从诸如磁盘文件,数据库,网络通讯等获得源数据,并提供给View,View对数据进行修改,然后再通过Model更新源数据. Model 另一个重要工作时为源数据添加索引(ModelIndex).列表形式采用row/colum编号,树形式为建立父子间的层次关系

Qt 事件处理机制

Qt 事件处理机制 因为这篇文章写得特别好,将Qt的事件处理机制能够阐述的清晰有条理,并且便于学习.于是就装载过来了(本文做了排版,并删减了一些冗余的东西,希望原主勿怪),以供学习之用. 简介 在Qt中,事件被封装成一个个对象,所有的事件均继承自抽象类QEvent.Qt是以事件驱动UI工具集.Signals/Slots在多线程中的实现也是依赖于Qt的事件处理机制.在Qt中,事件被封装成一个个对象,所有的事件都继承抽象基类QEvent. Qt事件处理机制 产生事件:输入设备,键盘鼠标等.keyPr

QT开发(六十三)——QT事件机制分析

QT开发(六十三)--QT事件机制分析 一.事件机制 事件是由系统或者QT平台本身在不同的时刻发出的.当用户按下鼠标.敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件.一些事件在对用户操作做出响应时发出,如键盘事件等:另一些事件则是由系统自动发出,如计时器事件. 事件的出现,使得程序代码不会按照原始的线性顺序执行.线性顺序的程序设计风格不适合处理复杂的用户交互,如用户交互过程中,用户点击"打开文件"将开始执行打开文件的操作,用户点击"保存文件"将开始执

Qt事件机制概览

Qt事件机制概览 Qt事件机制概览 消息循环 Qt事件循环 简介 QEventLoop 跨线程的信号和槽与事件循环 模态窗口 Native widget or Alien widget 创建Native widget 创建QApplication的message-only窗口 派发事件的公共基础方法 source code QApplication的创建过程 QWidget native QWidget 的创建过程 普通native widget回调过程 QApplication的message

【转】解读Qt 事件处理机制(上篇)

[转自]:http://mobile.51cto.com/symbian-272812.htm 在Qt中,事件被封装成一个个对象,所有的事件均继承自抽象类QEvent. 接下来依次谈谈Qt中有谁来产生.分发.接受和处理事件. 本篇来介绍Qt 事件处理机制 .深入了解事件处理系统对于每个学习Qt人来说非常重要,可以说,Qt是以事件驱动的UI工具集. 大家熟知Signals/Slots在多线程的实现也依赖于Qt的事件处理机制. 在Qt中,事件被封装成一个个对象,所有的事件均继承自抽象类QEvent.

浅析在QtWidget中自定义Model

Qt 4推出了一组新的item view类,它们使用model/view结构来管理数据与表示层的关系.这种结构带来的功能上的分离给了开发人员更大的弹性来定制数据项的表示,它也提供一个标准的model接口,使得更多的数据源可以被这些item view使用.这里对model/view的结构进行了描述,结构中的每个组件都进行了解释.. 一直觉得Qt里的Model-View概念极其神秘, 因为看过很多一知半解的source code, 却总是咋看咋不懂,急了满头大汗之余不禁感叹 — 老了,脑子不够用了!

QT开发(十二)——QT事件处理机制

QT开发(十二)--QT事件处理机制 一.QT事件简介 QT程序是事件驱动的, 程序的每个动作都是由内部某个事件所触发.QT事件的发生和处理成为程序运行的主线,存在于程序整个生命周期. 常见的QT事件类型如下: 键盘事件: 按键按下和松开 鼠标事件: 鼠标移动,鼠标按键的按下和松开 拖放事件: 用鼠标进行拖放 滚轮事件: 鼠标滚轮滚动 绘屏事件: 重绘屏幕的某些部分 定时事件: 定时器到时 焦点事件: 键盘焦点移动 进入和离开事件: 鼠标移入widget之内,或是移出 移动事件: widget的

9、Qt 事件处理机制

原文地址:http://mobile.51cto.com/symbian-272812.htm 在Qt中,事件被封装成一个个对象,所有的事件均继承自抽象类QEvent. 接下来依次谈谈Qt中有谁来产生.分发.接受和处理事件. 本篇来介绍Qt 事件处理机制.深入了解事件处理系统对于每个学习Qt人来说非常重要,可以说,Qt是以事件驱动的UI工具集. 大家熟知Signals/Slots在多线程的实现也依赖于Qt的事件处理机制 在Qt中,事件被封装成一个个对象,所有的事件均继承自抽象类QEvent.