1. 程式人生 > >QRowTable表格控制元件(四)-效率優化之-優化資料來源

QRowTable表格控制元件(四)-效率優化之-優化資料來源

目錄

  • 一、開心一刻
  • 二、問題分析
  • 三、重寫資料來源
    • 1、自己儲存資料
    • 2、重寫data介面
  • 四、比較
  • 五、相關文章

原文連結:QRowTable表格控制元件(四)-效率優化之-優化資料來源

一、開心一刻

一程式設計師第一次上女朋友家她媽板著臉問 :你想娶我女兒,有多少存款?

程式設計師低了下頭:五百!

她媽更鄙視了:才五百塊,買個廁所都不夠!

程式設計師忙說:不是人民幣!

她媽:就算是美元,還是不夠買廁所!

程式設計師:其實是比特幣!

她媽:哇,賢婿,我給你買只大龍蝦去

二、問題分析

前邊已經寫了3篇關於表格控制元件的功能,分別是QRowTable表格控制元件-支援hover整行、checked整行、指定列排序等、QRowTable表格控制元件(二)-紅漲綠跌和QRowTable表格控制元件(三)-效率優化之-合理使用QStandardItem,這三篇文章主要是圍繞實現核心功能來講述的一般實現方式,當資料量多大時就會出現效能問題。

既然出現問題,當然是需要解決的。本篇文章就來講述怎麼處理大量資料的情況。

首先我們先來分析下上述幾種實現方式為什麼會比較消耗時間,首先程式碼量也不大,在程式碼裡隨機打幾個斷點,我們就會發現,程式碼在迴圈構造QStandardItem這個結構中耗費的時間比較久,並且當for迴圈出現上萬次迴圈時尤為明顯。

找到問題後,就是想辦法怎麼可以更少的呼叫構造QStandardItem這個流程,當然了Qt也給我們提供了很好的解決方案,那就是重寫資料來源(Model)。

三、重寫資料來源

Qt中包含有經典的MVC模式,比如我們經常使用的QStandardItemModel、QTableView和QStyledItemDelegate,當我們要實現一個高效的表格控制元件時,重寫這3個類基本就可以完成我們所需要的功能。

當然了Qt還提供了了一層資料快取層QSortFilterProxyModel,這個類可以幫助我們更好的實現排序、模糊搜尋功能

本篇文章這裡只講解重寫資料來源,關於其他兩個類的重寫前面文章中應該有所講述,這裡不再過多解釋。

下面一起來看下資料來源的重寫方式,我們這裡選擇繼承自QStandardItemModel這個類來實現我們的資料來源,這裡是一個偷懶的方式,正常情況下是需要重寫QAbstractItemModel類,如果重寫QAbstractItemModel類的話,那麼就需要重寫更多的介面。

class QRowModel : public QStandardItemModel
{
    Q_OBJECT

public:
    explicit QRowModel(QObject * parent = 0);
    ~QRowModel();
public:
    //設定資料來源
    void SetSourceData(const TradeOrderInfoList & data);
    ...

protected:
    virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    virtual void sort(int column, Qt::SortOrder order /* = Qt::AscendingOrder */) override;

private:
    ...
    TradeOrderInfoList itemList;
    QColor m_CheckedColor = QColor("#4F4F4F");
    mutable std::map <int, int> m_AlignmentList;//列對其方式

    friend class QRowTable;
};

上次程式碼是重寫Model類的標頭檔案,其中有一些不相干的程式碼我選擇了隱藏,重寫Model最重要的就是需要我們自己去儲存資料,並且在Qt的呼叫機制呼叫獲取資料時給他返回即可。

關鍵點

  1. 重寫Model,自己儲存資料
  2. 重寫data介面,返回資料

1、自己儲存資料

自己儲存資料有一個好處,那就是我們在給Model設定資料時,最大的效能損耗就是資料拷貝的過程,仔細想想這個是不是都不是問題。

上述程式碼中的TradeOrderInfoList這個介面提就是我們自己定義的一個容器介面,方便儲存我們的表格資料,當檢視繪製時,會從這裡拿資料。

2、重寫data介面

資料已經準備完畢,接下里就是View如何優雅的拿到資料並繪製了,這裡我們重點講述怎麼拿資料,如何繪製是QStyledItemDelegate這個類的事,感興趣的可以自己研究研究。

仔細檢視Model的版主文件們就會發現有一個data介面函式,他的宣告可能像下面這樣

QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;

們的任務就是重寫這個介面,返回指定索引上的指定型別資料

  1. index:表格cell的索引,包含有行和列序號
  2. role:表格資料型別,每一個cell上都包含有一系列鍵值對,方便儲存單元格上的各種資料,比如說前景色、背景色、字型、位置、高亮色、背景畫刷等等。
QVariant QRowModel::data(const QModelIndex &index, int role) const
{
    if (Qt::DecorationRole == role)
    {
        int r = index.row();
        int c = index.column();
        if (r >= itemList.size())
        {
            return "";
        }
        const TradeOrderInfo & info = itemList.at(r);
        switch (c)
        {
        case 0:
            return QPixmap(stock_helper::getCurrencyIcon(info.market, info.symbol).c_str());
        default:
            "";
            break;
        }
    }
    else if (Qt::ForegroundRole == role)
    {
        int r = index.row();
        int c = index.column();
        if (r >= itemList.size())
        {
            return "";
        }
        const TradeOrderInfo & info = itemList.at(r);
        switch (c)
        {
        case 4://"方向"
            if (info.action.compare("SELL") == 0)
            {
                return QColor("#218DF2");
            }
            else
            {
                return QColor("#FF4A4A");
            }
        default:
            return QColor("#dddddd");
        }
    }
    else if (Qt::DisplayRole == role)
    {
        //自己從model中拿資料給view
        //"名稱"
        int r = index.row();
        int c = index.column();
        if (r >= itemList.size())
        {
            return "";
        }
        const TradeOrderInfo & info = itemList.at(r);
        switch (c)
        {
        case 0://"名稱" 
            return stock_helper::OrderDisplayName(&info);
        case 1://"程式碼" 
            return stock_helper::OrderDisplaySymbol(&info, m_strAccount);
        case 2://"成交量" 數字居右
            return QString::number(info.totalQuantity);
        case 3://"成交均價" 數字居右
            return stock_helper::PriceDisplayName(info.symbol, info.market, info.secType, info.avgFillPrice);
        case 4://"方向"
            if (info.action.compare("SELL") == 0)
            {
                return QUI_LOAD_STRING(TTS_ORDER_DIR_SELL);
            }
            else
            {
                return QUI_LOAD_STRING(TTS_ORDER_DIR_BUY);
            }
        default:
            "";
            break;
        }
    }

    return QStandardItemModel::data(index, role);
}

別忘啦,當資料來源發生變化的時候使用SetSourceData介面更新下。

資料來源重寫好以後,再試試我們的效能是不是槓槓滴。

四、比較

本篇文章應該是實現表格功能的最後一篇文章了,可以滿足大多數的產品需求。

後續可能還會陸續出一些更友好的互動優化,敬請期待。

下面是一個表格,包含了傳統的表格資料來源和重寫後的表格資料來源優劣比較。

比較專案 | 傳統方式 | 重寫Model --- | --- | --- 難易程度 | 簡單 | 複雜 程式碼裡 | 少 | 多 效能 | 差 | 好 推薦度 | 兩顆星 | 五顆星

五、相關文章

  1. Qt實現表格控制元件-支援多級列表頭、多級行表頭、單元格合併、字型設定等

  2. Qt高仿Excel表格元件-支援凍結列、凍結行、內容自適應和合並單元格

  3. 屬性瀏覽器控制元件QtTreePropertyBrowser編譯成動態庫(設計師外掛)

  4. 超級實用的屬性瀏覽器控制元件--QtTreePropertyBrowser

  5. Qt之表格控制元件螞蟻線

  6. QRowTable表格控制元件-支援hover整行、checked整行、指定列排序等

  7. QRowTable表格控制元件(二)-紅漲綠跌

  8. QRowTable表格控制元件(三)-效率優化之-合理使用QStandardItem


值得一看的優秀文章:

  1. 財聯社-產品展示
  2. 廣聯達-產品展示
  3. Qt定製控制元件列表
  4. 牛逼哄哄的Qt庫





如果您覺得文章不錯,不妨給個打賞,寫作不易,感謝各位的支援。您的支援是我最大的動力,謝謝!!!














很重要--轉載宣告

  1. 本站文章無特別說明,皆為原創,版權所有,轉載時請用連結的方式,給出原文出處。同時寫上原作者:朝十晚八 or Twowords

  2. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時通過修改本文達到有利於轉載者的目的。