[TOC] 原文鏈接: "QRowTable表格控制項(四) 效率優化之 優化數據源" 一、開心一刻 一程式員第一次上女朋友家她媽板著臉問 :你想娶我女兒,有多少存款? 程式員低了下頭:五百! 她媽更鄙視了:才五百塊,買個廁所都不夠! 程式員忙說:不是人民幣! 她媽:就算是美元,還是不夠買廁所! 程式 ...
目錄
原文鏈接: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的調用機制調用獲取數據時給他返回即可。
關鍵點
- 重寫Model,自己存儲數據
- 重寫data介面,返回數據
1、自己存儲數據
自己存儲數據有一個好處,那就是我們在給Model設置數據時,最大的性能損耗就是數據拷貝的過程,仔細想想這個是不是都不是問題。
上述代碼中的TradeOrderInfoList這個介面提就是我們自己定義的一個容器介面,方便存儲我們的表格數據,當視圖繪製時,會從這裡拿數據。
2、重寫data介面
數據已經準備完畢,接下里就是View如何優雅的拿到數據並繪製了,這裡我們重點講述怎麼拿數據,如何繪製是QStyledItemDelegate這個類的事,感興趣的可以自己研究研究。
仔細查看Model的版主文檔們就會發現有一個data介面函數,他的聲明可能像下麵這樣
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
們的任務就是重寫這個介面,返回指定索引上的指定類型數據
- index:表格cell的索引,包含有行和列序號
- 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介面更新下。
數據源重寫好以後,再試試我們的性能是不是杠杠滴。
四、比較
本篇文章應該是實現表格功能的最後一篇文章了,可以滿足大多數的產品需求。
後續可能還會陸續出一些更友好的交互優化,敬請期待。
下麵是一個表格,包含了傳統的表格數據源和重寫後的表格數據源優劣比較。
五、相關文章
值得一看的優秀文章:
如果您覺得文章不錯,不妨給個打賞,寫作不易,感謝各位的支持。您的支持是我最大的動力,謝謝!!!
很重要--轉載聲明
本站文章無特別說明,皆為原創,版權所有,轉載時請用鏈接的方式,給出原文出處。同時寫上原作者:朝十晚八 or Twowords
如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時通過修改本文達到有利於轉載者的目的。