Qt 內建的 QStringListModel 等預定義模型雖方便,但無法滿足複雜業務需求(如資料壓縮、運算衍生、效能優化)。本篇透過「貨幣匯率表」實例,示範繼承 QAbstractTableModel 實作高效能、低記憶體佔用的自訂表格模型。
假設需顯示 100 種貨幣兩兩匯率的 100×100 表格(含自對自 1.0000),共 10,000 儲存格。若全量儲存極其浪費。觀察發現:**僅需儲存各貨幣對美元匯率(100 筆),任意兩貨幣匯率可由「幣值A/幣值B」即時運算得出**。
class CurrencyModel : public QAbstractTableModel
{
public:
CurrencyModel(QObject *parent = 0);
void setCurrencyMap(const QMap<QString, double> &map);
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
private:
QString currencyAt(int offset) const;
QMap<QString, double> currencyMap; // 底層資料:貨幣名稱 -> 對美元匯率
};
int CurrencyModel::rowCount(const QModelIndex &) const
{ return currencyMap.count(); }
int CurrencyModel::columnCount(const QModelIndex &) const
{ return currencyMap.count(); }
QVariant CurrencyModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) return QVariant();
// 文字靠右垂直置中
if (role == Qt::TextAlignmentRole)
return int(Qt::AlignRight | Qt::AlignVCenter);
// 顯示角色:動態計算匯率
if (role == Qt::DisplayRole) {
QString rowCur = currencyAt(index.row());
QString colCur = currencyAt(index.column());
double rateRow = currencyMap.value(rowCur);
double rateCol = currencyMap.value(colCur);
if (rateRow == 0.0) return "####"; // 避免除零
double amount = rateCol / rateRow; // 幣值B / 幣值A
return QString("%1").arg(amount, 0, 'f', 4); // 格式化 4 位小數
}
return QVariant();
}
QVariant CurrencyModel::headerData(int section, Qt::Orientation, int role) const
{
if (role != Qt::DisplayRole) return QVariant();
return currencyAt(section); // 行/列標題皆為貨幣名稱
}
void CurrencyModel::setCurrencyMap(const QMap<QString, double> &map)
{
currencyMap = map;
reset(); // 通知視圖資料全量變更
}
QString CurrencyModel::currencyAt(int offset) const
{
return (currencyMap.begin() + offset).key();
}
data() 回傳 QVariant,相當於 Java 的 Object,可封裝 int、QString、QColor 等任意型別。使用時需對應型別取出(如 toInt()、toString()),不可自動轉型。Qt 將此功能從 QObject 分離,避免基底類別膨脹,體現 C++ 非單一繼承體系下的務實設計。
QMap<QString, double> data;
data["NOK"] = 1.0000;
data["NZD"] = 0.2254;
data["SEK"] = 1.1991;
data["SGD"] = 0.2592;
data["USD"] = 0.1534;
CurrencyModel *model = new CurrencyModel;
model->setCurrencyMap(data);
QTableView *view = new QTableView(this);
view->setModel(model);
view->resize(400, 300);

三者關係:QAbstractItemModel 為根,QAbstractListModel 與 QAbstractTableModel 分別針對一維/二維優化。
本文出自 “豆子空間” 博客,請務必保留此出處:https://devbean.blog.51cto.com/448512/267435