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類來存儲數據庫表的每一條記錄。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM