第一部分:用超市系统理解MVC
想象一个现代化超市的运作:
-
仓库(模型):存放所有商品和库存数据
-
只关心数据本身,不关心如何展示
-
当库存变化时自动通知货架和收银台
-
-
货架(视图):展示商品给顾客的不同方式
-
水果区用平铺展示,饮料区用立式冰柜
-
同一批可乐数据,在不同区域展示形式不同
-
-
售货员(委托):处理顾客与商品的交互
-
帮助顾客试吃(编辑数据)
-
给商品贴促销标签(自定义显示)
-
检查顾客年龄是否够买烟(数据验证)
-
第二部分:模型详解 - 超市的仓库管理系统
基础模型就像不同的记录本:
-
一、小本本(QStringListModel)
-
就像便利贴,只记水果名称:["苹果","香蕉"]
-
适用场景:简单的待办事项列表
// 创建购物清单 QStringList shoppingList; shoppingList << "牛奶" << "面包" << "鸡蛋"; // 建立模型 QStringListModel listModel; listModel.setStringList(shoppingList); // 显示清单 QListView listView; listView.setModel(&listModel);
-
-
二、Excel表(QStandardItemModel)
-
带有多列信息的商品清单:
条形码 商品名 价格 库存 1001 可乐 3.5 50 -
可以随时添加行列
// 创建商品库存表 QStandardItemModel tableModel; tableModel.setHorizontalHeaderLabels({"条形码","商品名","价格","库存"}); // 添加一行数据 QList<QStandardItem*> rowItems; rowItems << new QStandardItem("1001") << new QStandardItem("可乐") << new QStandardItem("3.5") << new QStandardItem("50"); tableModel.appendRow(rowItems); // 显示表格 QTableView tableView; tableView.setModel(&tableModel);
-
-
三、树形仓库(QFileSystemModel)
像超市仓库的货架分类:- 零食区
- 饮料区
- 碳酸饮料
- 可乐
- 雪碧
- 果汁
- 碳酸饮料
// 创建仓库目录模型
QFileSystemModel treeModel;
treeModel.setRootPath("C:/SuperMarket/Warehouse");
// 显示树形结构
QTreeView treeView;
treeView.setModel(&treeModel);
treeView.setRootIndex(treeModel.index("C:/SuperMarket/Warehouse"));
第三部分:视图详解 - 超市的各种展示方式
同一批商品数据的不同展示:
// 假设我们已经有一个商品模型
QStandardItemModel productModel;
// ...(填充商品数据)...
// 展示方式1:便利货架(列表视图)
QListView listView;
listView.setModel(&productModel);
listView.setViewMode(QListView::IconMode); // 图标模式
// 展示方式2:价目表(表格视图)
QTableView tableView;
tableView.setModel(&productModel);
// 展示方式3:仓库导航(树形视图)
QTreeView treeView;
treeView.setModel(&productModel);
第四部分:委托详解 - 超市的增值服务
自定义商品展示和交互:
-
特价标签:红色显示打折商品
-
试吃台:编辑商品信息的自定义界面
-
年龄验证:购买烟酒时的特殊检查
class ProductDelegate : public QStyledItemDelegate {
public:
// 如何绘制商品项
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
if(index.column() == 2) { // 价格列
double price = index.data().toDouble();
if(price < 5.0) { // 低价商品标红
painter->fillRect(option.rect, Qt::red);
}
}
QStyledItemDelegate::paint(painter, option, index);
}
// 创建特价商品编辑器
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
if(index.column() == 1) { // 商品名列
QLineEdit *editor = new QLineEdit(parent);
editor->setFrame(false);
editor->setMaxLength(20);
return editor;
}
return QStyledItemDelegate::createEditor(parent, option, index);
}
};
// 使用委托
ProductDelegate delegate;
tableView.setItemDelegate(&delegate);
第五部分:信号与槽 - 超市的广播系统
当仓库(模型)发生变化时,自动通知所有相关方:
// 当商品数据变化时(如价格调整)
connect(&productModel, &QStandardItemModel::dataChanged,
[](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
qDebug() << "以下商品信息已更新:从行" << topLeft.row()
<< "到行" << bottomRight.row();
});
// 当库存不足时触发报警
connect(&productModel, &QStandardItemModel::rowsAboutToBeRemoved,
[](const QModelIndex &parent, int start, int end) {
qDebug() << "警告:以下商品即将缺货,行号:" << start << "到" << end;
});
第六部分:实战案例 - 开发超市管理系统
#include <QApplication>
#include <QStandardItemModel>
#include <QTableView>
#include <QHeaderView>
class SupermarketSystem : public QWidget {
public:
SupermarketSystem(QWidget *parent = nullptr) : QWidget(parent) {
setupModel();
setupViews();
setupLayout();
loadData();
}
private:
void setupModel() {
model = new QStandardItemModel(this);
model->setHorizontalHeaderLabels({"ID","商品名","价格","库存","类别"});
}
void setupViews() {
view = new QTableView;
view->setModel(model);
view->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
}
void setupLayout() {
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(view);
setLayout(layout);
}
void loadData() {
// 模拟从数据库加载数据
addProduct("1001", "可口可乐", 3.5, 50, "饮料");
addProduct("1002", "乐事薯片", 6.0, 30, "零食");
addProduct("1003", "金龙鱼油", 55.0, 20, "粮油");
}
void addProduct(const QString &id, const QString &name,
double price, int stock, const QString &category) {
QList<QStandardItem*> row;
row << new QStandardItem(id);
row << new QStandardItem(name);
row << new QStandardItem(QString::number(price));
row << new QStandardItem(QString::number(stock));
row << new QStandardItem(category);
model->appendRow(row);
}
QStandardItemModel *model;
QTableView *view;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
SupermarketSystem supermarket;
supermarket.resize(800, 600);
supermarket.setWindowTitle("超市库存管理系统");
supermarket.show();
return app.exec();
}
关键要点总结
-
模型是大脑:只负责管理数据,不知道如何显示
-
视图是外表:决定数据的展示方式,不关心数据存储
-
委托是交互:处理用户如何查看和修改数据
-
信号是广播:数据变化时自动通知所有相关视图更新
-
分离是优势:可以随意更换视图而不影响数据逻辑
就像超市可以随时调整货架布局而不影响仓库库存,QT的模型/视图结构让数据管理和显示完全解耦,大大提高了灵活性和可维护性。