QT模型/视图结构:用生活例子讲透技术原理

第一部分:用超市系统理解MVC

想象一个现代化超市的运作:

  1. 仓库(模型):存放所有商品和库存数据

    • 只关心数据本身,不关心如何展示

    • 当库存变化时自动通知货架和收银台

  2. 货架(视图):展示商品给顾客的不同方式

    • 水果区用平铺展示,饮料区用立式冰柜

    • 同一批可乐数据,在不同区域展示形式不同

  3. 售货员(委托):处理顾客与商品的交互

    • 帮助顾客试吃(编辑数据)

    • 给商品贴促销标签(自定义显示)

    • 检查顾客年龄是否够买烟(数据验证)

第二部分:模型详解 - 超市的仓库管理系统

基础模型就像不同的记录本:

  • 一、小本本(QStringListModel)

    • 就像便利贴,只记水果名称:["苹果","香蕉"]

    • 适用场景:简单的待办事项列表

      // 创建购物清单
      QStringList shoppingList;
      shoppingList << "牛奶" << "面包" << "鸡蛋";
      
      // 建立模型
      QStringListModel listModel;
      listModel.setStringList(shoppingList);
      
      // 显示清单
      QListView listView;
      listView.setModel(&listModel);

  • 二、Excel表(QStandardItemModel)

    • 带有多列信息的商品清单:

      条形码商品名价格库存
      1001可乐3.550
    • 可以随时添加行列

      // 创建商品库存表
      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);

第四部分:委托详解 - 超市的增值服务

自定义商品展示和交互:

  1. 特价标签:红色显示打折商品

  2. 试吃台:编辑商品信息的自定义界面

  3. 年龄验证:购买烟酒时的特殊检查

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();
}

关键要点总结

  1. 模型是大脑:只负责管理数据,不知道如何显示

  2. 视图是外表:决定数据的展示方式,不关心数据存储

  3. 委托是交互:处理用户如何查看和修改数据

  4. 信号是广播:数据变化时自动通知所有相关视图更新

  5. 分离是优势:可以随意更换视图而不影响数据逻辑

        就像超市可以随时调整货架布局而不影响仓库库存,QT的模型/视图结构让数据管理和显示完全解耦,大大提高了灵活性和可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值