承上篇唯讀模型,本篇進一步實作 **可編輯的對稱矩陣模型** —— 城市距離表。展示如何覆寫 setData()、flags() 實現資料雙向同步與編輯權限控制。
dist(A,B) == dist(B,A),對角線為 0。QVector<int> 緊湊存放,大小為 N*(N-1)/2。class CityModel : public QAbstractTableModel
{
Q_OBJECT
public:
CityModel(QObject *parent = 0);
void setCities(const QStringList &cityNames);
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
private:
int offsetOf(int row, int column) const; // 二維座標 -> 一維索引
QStringList cities;
QVector<int> distances; // 緊湊儲存三角矩陣
};
int CityModel::offsetOf(int row, int column) const
{
if (row < column) qSwap(row, column); // 統一轉為下三角索引
return (row * (row - 1) / 2) + column; // 三角數公式
}
QVariant CityModel::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) {
if (index.row() == index.column()) return 0; // 對角線
int offset = offsetOf(index.row(), index.column());
return distances[offset];
}
return QVariant();
}
bool CityModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
// 僅處理:合法索引、非對角線、編輯角色
if (index.isValid() && index.row() != index.column() && role == Qt::EditRole) {
int offset = offsetOf(index.row(), index.column());
distances[offset] = value.toInt(); // 更新儲存
// 建立對稱位置的 ModelIndex
QModelIndex transposedIndex = createIndex(index.column(), index.row());
// 發射 dataChanged 通知視圖刷新「兩個」儲存格
emit dataChanged(index, index);
emit dataChanged(transposedIndex, transposedIndex);
return true;
}
return false;
}
關鍵細節:
createIndex(row, col) 手動建立對稱位置的索引。dataChanged(topLeft, bottomRight) 兩次,分別通知原位置與對稱位置更新。true 表示編輯成功,false 則視圖會撤銷編輯。Qt::ItemFlags CityModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
if (index.row() != index.column()) // 對角線不可編輯
flags |= Qt::ItemIsEditable;
return flags;
}
void CityModel::setCities(const QStringList &cityNames)
{
cities = cityNames;
distances.resize(cities.count() * (cities.count() - 1) / 2);
distances.fill(0);
reset(); // 完整重置模型
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QStringList cities;
cities << "Arvika" << "Boden" << "Eskilstuna" << "Falun";
CityModel cityModel;
cityModel.setCities(cities);
QTableView tableView;
tableView.setModel(&cityModel);
tableView.setAlternatingRowColors(true);
tableView.setWindowTitle(QObject::tr("Cities"));
tableView.show();
return a.exec();
}

本例完整示範 **可編輯自訂模型** 的三大關鍵:
dataChanged。掌握此模式,即可應對各類對稱矩陣、三角矩陣等特殊資料結構的模型化需求。
本文出自 “豆子空間” 博客,請務必保留此出處:https://devbean.blog.51cto.com/448512/267972