QT內省機制、自定義Model、資料庫

来源:http://www.cnblogs.com/sfy5848/archive/2016/11/04/6030493.html
-Advertisement-
Play Games

本文將介紹自定義Model過程中資料庫數據源的獲取方法,我使用過以下三種方式獲取資料庫數據源: 創建 存儲對應資料庫所有欄位的 結構體,將結構體置於容器中返回,然後根據索引值(QModelIndex)取出最終的欄位值; 創建 存儲對應資料庫所有欄位的 類,將類對象置於容器中返回,然後利用內省機制獲取 ...


本文將介紹自定義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類來存儲資料庫表的每一條記錄。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • C#中枚舉的使用 1.原則上全部使用枚舉,不使用常量,除非常量是一個,不是一組 2.如果一組常量中增減常量後要對代碼修改,則要將這組常量定義為枚舉 3.如果一組常量中增減常量後代碼不需要修改,則要將這組常量存儲到字碼主檔中,由資料庫進行維護 枚舉擴展方法 1.將字元串轉為枚舉 2.獲取枚舉的描述,在 ...
  • Orchard CMS安裝後,配置文件和資料庫保存在App_Data目錄中。這個目錄是受保護的,是不能通過網址訪問到的。 如果要完全重裝你的站點,你可以刪除此目錄中的所有文件,但是最好先備份!刪除後重新訪問站點,就可以重新安裝Orchard CMS。 如果遇到問題,可參考以下鏈接:http://or ...
  • 一、 ID是設計的時候所指定的ID。 ClientID是當這個控制項生成到客戶端頁面時候,需要在客戶端訪問時候用的。 UniqueID是當需要參與服務端回傳的時候用的。 備註:當控制項是子控制項的時候(例如在用戶控制項中的Button),ClientID在HTML頁面中是作為控制項的ID屬性,UniqueID ...
  • C# DateTime與時間戳的相互轉換,包括JavaScript時間戳和Unix的時間戳。 ...
  • 面向過程就是分析解決問題所需要的步驟,然後用函數把這些步驟一步一步的實現出來,使用的時候一個一個依次調用就可以了。 面向對象就是把構成問題事務分解成各個對象,建立對象的目的不是為了完成一個步驟,而是為了描述某個事物在整個解決問題的步驟中的行為。以功能來劃分問題,而不是步驟 ...
  • 1.1概述 將對象組合成樹形結構以表示“部分-整體”的層次結構。組合(Composite)使用戶對單個對象和組合對象的使用具有一致性。這就是組合模式的定義。 如果一個對象包含另一個對象的引用,稱這樣的對象為組合對象。如果將當前組合對象作為一個整體的話,那麼它所包含的對象就是該整體的一部分。如果一個對 ...
  • 1.1概述 保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。這就是單件模式的定義。 在某些情況下,我們可能需要某個類只能創建一個對象,即不讓用戶用該類實例化出多於兩個的實例。 例如,在一個公文管理系統中,公文類的實例“公文文件”,需要將公章類的實例作為自己的一個成員,以表明自己是一個有效的公文 ...
  • 1.1概述 用原型實例指定創建對象的種類,並且通過複製這些原型創建新的對象。這就是原型模式的定義。 在某些情況下,可能不希望反覆使用類的構造方法創建許多對象,而是希望使用該類創建一個對象後,以該對象為原型得到該對象的若幹個複製品。也就是說,將一個對象定義為原型對象,要求改原型對象提供一個方法,使該原 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...