- Light-hearted Moment
A programmer's first time visiting his girlfriend's parents, her mother asks him: "If you want to marry my daughter, how much savings do you have?"
The programmer looks down and says: "Five hundred!"
Her mother scoffs: "Only five hundred? Not even enough to buy a toilet!"
The programmer quickly replies: "It's not RMB!"
Her mother: "Even if it were USD, it still wouldn't cover a toilet!"
The programmer: "Actually, it's Bitcoin!"
Her mother: "Wow, son-in-law, I'll buy you a big lobster!"
- Problem Analysis
In the previous three articles about table controls, we covered functionalities like hover row support, checked rows, and column-specific sorting. These focused on implementing core features using general aprpoaches. When dealing with large datasets, performance issues become apparent.
When problems arise, solutions must be found. This article explores how to handle scenarios with massive amounts of data effectively.
Firstly, let's analyze why the previous implementations consume significant time. Although the code isn’t extensive, placing breakpoints reveals that constructing QStandardItem objects takes considerable time—especially noticeable during tens of thousands of iterations.
With this insight, the key is minimizing calls to construct QStandardItem objects. Qt offers an excellent solution: rewriting the model layer.
- Rewriting the Data Source
Qt implements the classic MVC pattern, including QStandardItemModel, QTableView, and QStyledItemDelegate. For high-performance table controls, rewriting these three components typically suffices.
Qt also provides a caching layer, QSortFilterProxyModel, which helps implement sorting and fuzzy search efficiently.
This article focuses solely on rewriting the data source. Other components were discussed in prior articles; hence, further explanation is omitted.
Below is the implementation approach by inheriting QStandardItemModel. While this is a shortcut, normally one would inherit QAbstractItemModel, requiring more interface overrides.
class QRowModel : public QStandardItemModel
{
Q_OBJECT
public:
explicit QRowModel(QObject * parent = 0);
~QRowModel();
public:
// Set data source
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; // Column alignment settings
friend class QRowTable;
};
</int>
As shown, the header file includes some irrelevant code. The critical part is storing data within our custom model and returning it upon Qt’s data requests.
Key Points
- Rewrite the Model to store data independently
- Override the data interface to provide data
1. Custom Data Storage
Storing data manually eliminates performance bottlenecks during copying, especially crucial when setting large datasets.
The TradeOrderInfoList type represents a container we define for efficient storage of table data. The view retrieves data from here during rendering.
2. Override the data Interface
With data prepared, the next step involves how the view retrieves and renders it. The drawing logic lies with QStyledItemDelegate, which we won’t delve into here.
The data function declaration is as follows:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Our responsibility is to return specified data types at given indices.
index: Row and column position of the cellrole: Data type associated with the cell, containing key-value pairs for various properties like foreground color, background color, font, alignment, highlight, and brush.
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:
return "";
}
}
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: // "Direction"
if (info.action.compare("SELL") == 0)
{
return QColor("#218DF2");
}
else
{
return QColor("#FF4A4A");
}
default:
return QColor("#dddddd");
}
}
else if (Qt::DisplayRole == role)
{
// Retrieve data from model for view
int r = index.row();
int c = index.column();
if (r >= itemList.size())
{
return "";
}
const TradeOrderInfo & info = itemList.at(r);
switch (c)
{
case 0: // "Name"
return stock_helper::OrderDisplayName(&info);
case 1: // "Code"
return stock_helper::OrderDisplaySymbol(&info, m_strAccount);
case 2: // "Volume" (right-aligned number)
return QString::number(info.totalQuantity);
case 3: // "Average Price" (right-aligned number)
return stock_helper::PriceDisplayName(info.symbol, info.market, info.secType, info.avgFillPrice);
case 4: // "Direction"
if (info.action.compare("SELL") == 0)
{
return QUI_LOAD_STRING(TTS_ORDER_DIR_SELL);
}
else
{
return QUI_LOAD_STRING(TTS_ORDER_DIR_BUY);
}
default:
return "";
}
}
return QStandardItemModel::data(index, role);
}
Remember to call SetSourceData when ever data changes.
- Comparison
This article concludes our series on table controls, satisfying most product needs.
Future updates may introduce more interactive enhancements—stay tuned!
| Comparison Item | Traditional Approach | Custom Model |
|---|---|---|
| Difficulty | Simple | Complex |
| Code Volume | Less | More |
| Performance | Poor | Good |
| Recommendation | Two Stars | Five Stars |
- Related Articles
- Qt Table Control Implementation - Multi-level Headers, Merged Cells, Font Settings
- High-Fidelity Excel-like Table Component - Freeze Columns/Rows, Auto-sizing, Merged Cells
- QtTreePropertyBrowser Property Browser Control - Compiled as Dynamic Library (Designer Plugin)
- Super Useful Property Browser Control -- QtTreePropertyBrowser
- Qt Table Control - Ant Line Style
- QRowTable Table Control - Hover Rows, Checked Rows, Column Sorting
- QRowTable Table Control (II) - Red/Green Up/Down Indicators
- QRowTable Table Control (III) - Efficiency Optimization - Proper Use of QStandardItem
Recommended Reading:
- Caixin - Product Showcase
- Glodon - Product Showcase
- Qt Custom Controls List
- Impressive Qt Libraries
- All articles are original unless otherwise stated. Copyright belongs to the author. Please link back to the original article and credit the author: "朝十晚八 or Twowords".
- If you wish to reprint, please do so verbatim. Modifications are not allowed without prior consent. Any alterations intended to benefit the reprinter are strictly prohibited.