<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                #(49):自定義只讀模型 model/view 模型將數據與視圖分割開來,也就是說,我們可以為不同的視圖,`QListView`、`QTableView`和`QTreeView`提供一個數據模型,這樣我們可以從不同角度來展示數據的方方面面。但是,面對變化萬千的需求,Qt 預定義的幾個模型是遠遠不能滿足需要的。因此,我們還必須自定義模型。 類似`QAbstractView`類之于自定義視圖,`QAbstractItemModel`?為自定義模型提供了一個足夠靈活的接口。它能夠支持數據源的層次結構,能夠對數據進行增刪改操作,還能夠支持拖放。不過,有時候一個靈活的類往往顯得過于復雜,所以,Qt 又提供了`QAbstarctListModel`和`QAbstractTableModel`兩個類來簡化非層次數據模型的開發。顧名思義,這兩個類更適合于結合列表和表格使用。 本節,我們正式開始對自定義模型進行介紹。 在開始自定義模型之前,我們首先需要思考這樣一個問題:我們的數據結構適合于哪種視圖的顯示方式?是列表,還是表格,還是樹?如果我們的數據僅僅用于列表或表格的顯示,那么`QAbstractListModel`或者`QAbstractTableModel`?已經足夠,它們為我們實現了很多默認函數。但是,如果我們的數據具有層次結構,并且必須向用戶顯示這種層次,我們只能選擇`QAbstractItemModel`。不管底層數據結構是怎樣的格式,最好都要直接考慮適應于標準的`QAbstractItemModel`的接口,這樣就可以讓更多視圖能夠輕松訪問到這個模型。 現在,我們開始自定義一個模型。這個例子修改自《C++ GUI Programming with Qt4, 2nd Edition》。首先描述一下需求。我們想要實現的是一個貨幣匯率表,就像銀行營業廳墻上掛著的那種電子公告牌。當然,你可以選擇`QTableWidget`。的確,直接使用`QTableWidget`確實很方便。但是,試想一個包含了 100 種貨幣的匯率表。顯然,這是一個二維表,并且對于每一種貨幣,都需要給出相對于其他 100 種貨幣的匯率(我們把自己對自己的匯率也包含在內,只不過這個匯率永遠是 1.0000)。現在,按照我們的設計,這張表要有 100 x 100 = 10000 個數據項。我們希望減少存儲空間,有沒有更好的方式?于是我們想,如果我們的數據不是直接向用戶顯示的數據,而是這種貨幣相對于美元的匯率,那么其它貨幣的匯率都可以根據這個匯率計算出來了。比如,我存儲人民幣相對美元的匯率,日元相對美元的匯率,那么人民幣相對日元的匯率只要作一下比就可以得到了。這種數據結構就沒有必要存儲 10000 個數據項,只要存儲 100 個就夠了(實際情況中這可能是不現實的,因為兩次運算會帶來更大的誤差,但這不在我們現在的考慮范疇中)。 于是我們設計了`CurrencyModel`類。它底層使用`QMap<QString, double>`數據結構進行存儲,`QString`類型的鍵是貨幣名字,`double`類型的值是這種貨幣相對美元的匯率。(這里提一點,實際應用中,永遠不要使用 double 處理金額敏感的數據!因為 double 是不精確的,不過這一點顯然不在我們的考慮中。) 首先從頭文件開始看起: ~~~ class CurrencyModel : public QAbstractTableModel { public: CurrencyModel(QObject *parent = 0); void setCurrencyMap(const QMap<QString, double> &map); int rowCount(const QModelIndex &parent) const; int columnCount(const QModelIndex &parent) const; QVariant data(const QModelIndex &index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; private: QString currencyAt(int offset) const; QMap<QString, double> currencyMap; }; ~~~ 這段代碼平淡無奇,我們繼承了`QAbstractTableModel`類,然后重寫了所要求的幾個函數。構造函數同樣如此: ~~~ CurrencyModel::CurrencyModel(QObject *parent) : QAbstractTableModel(parent) { } ~~~ `rowCount()`和`columnCount()`用于返回行和列的數目。記得我們保存的是每種貨幣相對美元的匯率,而需要顯示的是它們兩兩之間的匯率,因此這兩個函數都應該返回這個 map 的項數: ~~~ int CurrencyModel::rowCount(const QModelIndex & parent) const { return currencyMap.count(); } int CurrencyModel::columnCount(const QModelIndex & parent) const { return currencyMap.count(); } ~~~ `headerData()`用于返回列名: ~~~ QVariant CurrencyModel::headerData(int section, Qt::Orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } return currencyAt(section); } ~~~ 我們在前面的章節中介紹過有關角色的概念。這里我們首先判斷這個角色是不是用于顯示的,如果是,則調用`currencyAt()`函數返回第 section 列的名字;如果不是則返回一個空白的`QVariant`對象。`currencyAt()`函數定義如下: ~~~ QString CurrencyModel::currencyAt(int offset) const { return (currencyMap.begin() + offset).key(); } ~~~ 如果不了解`QVariant`類,可以簡單認為這個類型相當于 Java 里面的 Object,它把 Qt 提供的大部分數據類型封裝起來,起到一個類型擦除的作用。比如我們的單元格的數據可以是 string,可以是 int,也可以是一個顏色值,這么多類型怎么使用一個函數返回呢?回憶一下,返回值并不用于區分一個函數。于是,Qt 提供了`QVariant`類型。你可以把很多類型存放進去,到需要使用的時候使用一系列的 to 函數取出來即可。比如把 int 包裝成一個 QVariant,使用的時候要用`QVariant::toInt()`重新取出來。這非常類似于 union,但是 union 的問題是,無法保持沒有默認構造函數的類型,于是 Qt 提供了`QVariant`作為 union 的一種模擬。 `setCurrencyMap()`函數則是用于設置底層的實際數據。由于我們不可能將這種數據硬編碼,所以我們必須為模型提供一個用于設置的函數: ~~~ void CurrencyModel::setCurrencyMap(const QMap<QString, double> &map) { beginResetModel(); currencyMap = map; endResetModel(); } ~~~ 我們當然可以直接設置 currencyMap,但是我們依然添加了`beginResetModel()`和`endResetModel()`兩個函數調用。這將告訴關心這個模型的其它類,現在要重置內部數據,大家要做好準備。這是一種契約式的編程方式。 接下來便是最復雜的`data()`函數: ~~~ QVariant CurrencyModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (role == Qt::TextAlignmentRole) { return int(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) { QString rowCurrency = currencyAt(index.row()); QString columnCurrency = currencyAt(index.column()); if (currencyMap.value(rowCurrency) == 0.0) { return "####"; } double amount = currencyMap.value(columnCurrency) / currencyMap.value(rowCurrency); return QString("%1").arg(amount, 0, 'f', 4); } return QVariant(); } ~~~ `data()`函數返回一個單元格的數據。它有兩個參數:第一個是`QModelIndex`,也就是單元格的位置;第二個是`role`,也就是這個數據的角色。這個函數的返回值是`QVariant`類型。我們首先判斷傳入的`index`是不是合法,如果不合法直接返回一個空白的`QVariant`。然后如果`role`是`Qt::TextAlignmentRole`,也就是文本的對齊方式,返回`int(Qt::AlignRight | Qt::AlignVCenter)`;如果是`Qt::DisplayRole`,就按照我們前面所說的邏輯進行計算,然后以字符串的格式返回。這時候你就會發現,其實我們在 if…else… 里面返回的不是一種數據類型:if 里面返回的是 int,而 else 里面是`QString`,這就是`QVariant`的作用了。 為了看看實際效果,我們可以使用這樣的`main()`函數代碼: ~~~ int main(int argc, char *argv[]) { QApplication a(argc, argv); QMap<QString, double> data; data["USD"] = 1.0000; data["CNY"] = 0.1628; data["GBP"] = 1.5361; data["EUR"] = 1.2992; data["HKD"] = 0.1289; QTableView view; CurrencyModel *model = new CurrencyModel(&view); model->setCurrencyMap(data); view.setModel(model); view.resize(400, 300); view.show(); return a.exec(); } ~~~ 這是我們的實際運行效果: [![](https://box.kancloud.cn/2015-12-29_56823265a530b.png)](http://files.devbean.net/images/2013/05/custom-model-r.png) 自定義只讀模型
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看