MVC(Model-View-Controller)架构是一种经典的软件设计模式,通过将应用程序划分为模型(Model)、视图(View)、控制器(Controller)三个核心组件,实现关注点分离(Separation of Concerns),旨在提升代码的可维护性、可扩展性及团队协作效率。自1979年由Smalltalk提出以来,MVC已成为Web开发、移动应用及桌面应用的主流架构模式,并随着技术演进不断适配现代开发需求。

一、MVC架构的核心组件与职责

MVC的核心逻辑是“数据-界面-控制”的分离,三个组件的职责边界清晰:

  • 模型(Model)

    负责数据管理与业务逻辑,是应用程序的“大脑”。它封装了数据的存储(如数据库交互)、验证(如输入合法性检查)及处理逻辑(如计算、转换)。模型独立于视图和控制器,可单独测试与修改,确保业务逻辑的一致性。

    示例:在电商应用中,模型可能包含Product类(封装商品的价格、库存等属性)、OrderService类(处理订单生成、支付逻辑)。

  • 视图(View)

    负责用户界面的展示,是用户与应用程序交互的“窗口”。它从模型获取数据,并将其渲染为用户可见的形式(如HTML页面、移动应用界面)。视图不包含业务逻辑,仅关注数据的呈现,确保界面的简洁性与可维护性。

    示例:在Web应用中,视图可能是Razor模板(ASP.NET MVC)、Thymeleaf模板(Spring MVC)或React组件(前端MVC)。

  • 控制器(Controller)

    负责协调模型与视图的交互,是“桥梁”角色。它接收用户的输入(如按钮点击、表单提交),调用模型的业务逻辑处理数据,然后将结果传递给视图进行渲染。控制器不包含业务逻辑,仅做数据适配与流程控制,确保输入与输出的正确性。

    示例:在Spring MVC中,控制器使用@RestController注解,通过@GetMapping映射请求路径,调用服务层获取数据后返回视图。

二、MVC架构的工作流程

MVC的典型工作流程可概括为“用户输入→控制器处理→模型更新→视图渲染”

  1. 用户交互:用户通过视图(如点击按钮、提交表单)发送请求。

  2. 控制器接收:控制器捕获用户输入,解析请求参数(如路径变量、表单数据)。

  3. 模型处理:控制器调用模型的业务逻辑(如查询数据库、计算数据),模型返回处理结果。

  4. 视图渲染:控制器将模型数据传递给视图,视图根据数据生成用户界面(如HTML页面、JSON响应)。

  5. 响应用户:视图将渲染后的结果返回给用户,完成一次交互循环。

示例:在ASP.NET MVC中,用户请求/products/{id},控制器ProductController通过@GetMapping映射请求,调用ProductService获取商品数据,然后将数据传递给Razor视图ProductDetail.cshtml进行渲染。

三、MVC架构的优势

MVC的核心价值在于“分离关注点”,其优势主要体现在:

  • 可维护性:各组件职责清晰,修改视图不影响模型,修改模型不影响控制器,降低了代码的耦合度。

  • 可扩展性:新增功能时,只需扩展对应的组件(如添加新视图、修改模型逻辑),无需重构整个应用程序。

  • 可测试性:模型可独立进行单元测试(如测试业务逻辑的正确性),控制器可模拟用户输入进行集成测试,视图的测试可通过自动化工具(如Selenium)完成。

  • 团队协作:设计师可专注于视图的设计,开发者可专注于模型的实现,测试人员可专注于各组件的测试,提升了团队协作效率。

四、MVC架构的演进与现代应用

随着Web技术的发展(如前端框架、微服务、响应式编程),MVC架构也在不断演进,适配现代开发需求:

  • 前端MVC:React、Vue.js等前端框架采用组件化设计,将视图与控制器融合(如React的Component类包含状态与渲染逻辑),形成“前端MVC”模式。例如,React组件通过state管理数据(模型),通过render方法渲染视图,通过事件处理(如onClick)扮演控制器的角色。

  • 后端MVC的强化:Spring MVC 5.0引入类型安全路径变量(如@PathVariable("id") Long userId)、全局异常处理(如@ControllerAdvice),提升了后端MVC的健壮性;ASP.NET Core MVC加强了依赖注入(DI)与中间件支持,简化了组件的集成。

  • 与微服务结合:在微服务架构中,每个微服务可采用MVC模式,将服务拆分为模型(数据处理)、视图(API响应)、控制器(请求路由)。例如,Spring Cloud中的网关模块与MVC深度整合,支持高级限流策略,提升了分布式系统的可扩展性。

五、MVC架构的应用场景

MVC架构适用于需要清晰结构、易于维护的应用程序,尤其是:

  • 企业级Web应用:如电商平台、金融系统、ERP系统,这些应用需要处理复杂的业务逻辑与数据交互,MVC的分离特性可有效降低代码复杂度。

  • 移动应用:如iOS、Android应用,MVC可将界面(View)与业务逻辑(Model)分离,提升应用的性能与可维护性。

  • 前端应用:如React、Vue.js项目,前端MVC模式可有效管理组件的状态与交互,提升用户体验。

六、总结

MVC架构是一种经久不衰的软件设计模式,其核心思想是“分离关注点”,通过模型、视图、控制器的协同工作,实现应用程序的可维护性、可扩展性与可测试性。随着技术的演进,MVC已从传统的后端模式扩展到前端、微服务等场景,成为现代软件开发的基础架构之一。无论是企业级Web应用、移动应用还是前端项目,MVC都能提供有效的架构支持,帮助开发者构建健壮、易维护的应用程序。

 

Qt中的MVC(Model-View-Controller)架构模型/视图/委托(Model/View/Delegate)形式实现,核心思想是数据与界面分离:模型负责管理数据,视图负责显示数据,委托负责数据的交互(绘制与编辑)。这种架构提高了代码的重用性和灵活性,允许同一数据通过不同视图展示,且视图修改不影响底层数据逻辑。

一、Qt MVC架构的核心组件

Qt的MVC架构由三大核心组件构成,分别承担不同的职责:

1. 模型(Model)

模型是数据的管理者,负责存储、组织和提供数据,不涉及界面逻辑。它通过抽象接口(如QAbstractItemModel)向视图提供数据,支持数据的增删改查,并通过信号通知视图数据变化。

  • 内置模型类

    Qt提供了多种预定义模型,适配不同数据结构:

    • QStringListModel:存储字符串列表(如待办事项列表);

    • QStandardItemModel:通用模型,可表示列表、表格、树形结构;

    • QFileSystemModel:访问本地文件系统(如文件浏览器);

    • QSqlTableModel:操作数据库表(如用户信息管理)。

  • 自定义模型:若内置模型无法满足需求,可通过继承QAbstractItemModel实现自定义模型(如处理复杂树形数据)。

2. 视图(View)

视图是数据的展示者,负责将模型中的数据以可视化方式呈现(如列表、表格、树形结构),并接收用户输入(如点击、滚动)。视图不存储数据,仅依赖模型提供的接口获取数据。

  • 内置视图类

    Qt提供了多种视图控件,适配不同展示需求:

    • QListView:以列表形式显示数据;

    • QTableView:以表格形式显示数据(如Excel表格);

    • QTreeView:以树形结构显示层级数据(如文件系统的目录结构)。

3. 委托(Delegate)

委托是数据与用户之间的交互桥梁,负责数据的绘制(如单元格样式)和编辑(如弹出输入框)。当用户修改数据时,委托将输入传递给模型更新数据。

  • 内置委托:Qt提供了默认委托(如QStyledItemDelegate),支持基本的文本绘制和编辑;

  • 自定义委托:若需定制交互(如用滑块编辑数值、用颜色选择器编辑颜色),可通过继承QAbstractItemDelegate实现自定义委托。

二、Qt MVC架构的工作流程

Qt MVC架构的工作流程围绕数据流动信号通信展开:

  1. 模型初始化:创建模型对象(如QStandardItemModel),并填充数据(如通过setData()方法设置单元格内容);

  2. 视图绑定模型:将视图对象(如QTableView)与模型关联(通过setModel()方法),视图从模型获取数据并渲染;

  3. 用户交互:用户通过视图进行操作(如点击单元格、滚动页面),视图将交互事件传递给委托;

  4. 数据处理:委托处理用户输入(如编辑单元格内容),将修改后的数据传递给模型;

  5. 数据更新通知:模型通过信号(如dataChanged())通知视图数据变化,视图自动刷新显示。

三、Qt MVC架构的优势

  1. 数据与界面分离:修改视图不影响模型逻辑,修改模型不影响视图展示,降低了代码耦合度;

  2. 高重用性:同一模型可通过不同视图展示(如列表数据和表格数据共享同一模型);

  3. 易扩展性:支持自定义模型和委托,适配复杂业务需求(如树形数据展示、自定义编辑控件);

  4. 信号通信机制:通过信号与槽实现组件间通信,避免了直接依赖,提高了代码的可维护性。

四、Qt MVC架构的应用场景

Qt MVC架构适用于需要清晰数据与界面分离的应用程序,常见场景包括:

  • 数据管理应用:如数据库管理系统(使用QSqlTableModel操作数据库表)、文件浏览器(使用QFileSystemModel访问文件系统);

  • 表格/列表应用:如待办事项列表(使用QStringListModel存储数据,QListView展示)、Excel-like表格(使用QStandardItemModelQTableView);

  • 层级数据应用:如组织架构图(使用QStandardItemModel表示树形结构,QTreeView展示)。

五、Qt MVC架构的示例(简单表格应用)

以下是一个使用Qt MVC架构实现的简单表格应用示例,展示了模型的创建、视图的绑定和数据的显示:

#include <QApplication>
#include <QTableView>
#include <QStandardItemModel>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    
    // 1. 创建模型(4行2列)
    QStandardItemModel model(4, 2);
    for (int row = 0; row < 4; ++row) {
        for (int col = 0; col < 2; ++col) {
            // 设置单元格数据(行号+列号)
            model.setData(model.index(row, col), QString("Row%1, Col%2").arg(row).arg(col));
        }
    }
    
    // 2. 创建视图(表格)
    QTableView tableView;
    tableView.setModel(&model); // 绑定模型
    
    // 3. 显示视图
    tableView.show();
    
    return app.exec();
}
  • 代码说明

    • 模型:使用QStandardItemModel创建一个4行2列的表格模型,并通过setData()方法填充数据;

    • 视图:使用QTableView创建表格视图,通过setModel()方法绑定模型;

    • 运行效果:窗口显示一个4行2列的表格,单元格内容为“RowX, ColY”。

六、Qt 6中的MVC架构变化

Qt 6对MVC架构的API基本保持兼容,主要改进在于性能优化(如模型数据更新的效率提升)和新特性支持(如更好的高DPI显示支持)。对于现有Qt 5项目,升级到Qt 6时无需大幅修改MVC相关代码。

总结

Qt的MVC架构(模型/视图/委托)是数据驱动界面的核心实现方式,通过分离数据、视图和交互逻辑,提高了应用程序的可维护性和扩展性。其内置的模型和视图类覆盖了常见需求,自定义模型和委托则支持复杂场景。无论是简单的列表应用还是复杂的数据库管理系统,Qt MVC架构都能提供有效的解决方案。

 

Qt MVC(实际为Model/View/Delegate范式)与传统MVC架构的核心差异在于组件职责划分交互机制,但二者均遵循“关注点分离”的核心思想。以下从相同点不同点展开详细对比:

一、相同点:核心设计思想一致

传统MVC与Qt MVC均以“分离关注点”为核心目标,通过拆分组件职责提升代码的可维护性可扩展性可测试性,具体表现为:

  1. 组件分工明确

    两者均包含模型(Model)视图(View)两类核心组件,且职责边界一致:

    • 模型(Model):负责数据管理与业务逻辑,是应用程序的“数据源”,提供标准化接口(如rowCount()data())供外部访问数据,不依赖视图或控制器。

    • 视图(View):负责数据可视化,将模型中的数据以用户可感知的形式(如列表、表格、树形结构)呈现,不包含业务逻辑。

  2. 数据与界面解耦

    传统MVC中模型与视图分离,Qt MVC进一步强化了这一特性——模型独立于视图,同一模型可绑定多个视图(如同一份数据同时以表格和图表展示),视图修改不影响模型逻辑。

二、不同点:Qt MVC的“简化与定制化”改进

Qt MVC并未完全遵循传统MVC的“三组件”结构,而是通过合并视图与控制器引入委托(Delegate)的方式,适配GUI应用的交互密集型需求,具体差异如下:

1. 组件结构:Qt MVC合并“视图与控制器”,引入“委托”

传统MVC的控制器(Controller)是独立组件,负责处理用户输入(如点击、输入)并协调模型与视图的交互。而Qt MVC将视图与控制器的功能合并,同时引入委托(Delegate)替代控制器的数据项交互职责,形成“Model-View-Delegate”三元结构:

  • 视图(View):不仅负责展示数据,还承担传统控制器中“用户交互路由”的角色(如接收按钮点击、列表双击等事件),通过信号槽机制将事件传递给模型或委托。

  • 委托(Delegate):替代传统控制器的“数据项编辑与渲染”职责,负责:

    • 数据项渲染:自定义单元格的绘制方式(如进度条、星级评分);

    • 编辑交互:创建编辑控件(如QLineEditQCalendarWidget)并处理用户输入;

    • 数据验证:对用户输入进行格式校验(如限制数字输入、日期格式)。

例如,在Qt中,用户双击表格单元格时,视图接收双击事件,委托创建QLineEdit控件供用户输入,输入完成后委托通过模型接口(如setData())提交修改,模型验证数据后触发dataChanged()信号,视图自动更新。

2. 交互机制:Qt MVC依赖“信号槽”,传统MVC依赖“控制器中介”

传统MVC中,控制器是模型与视图的“中介”:用户输入先传递给控制器,控制器解析后调用模型方法修改数据,再通知视图更新。而Qt MVC通过信号槽机制实现组件间的松耦合,无需控制器作为中介:

  • 模型→视图:模型数据修改时,通过dataChanged()信号通知所有关联视图自动更新;

  • 视图→委托:用户交互事件(如单元格编辑)通过信号传递给委托,委托处理后通过模型接口修改数据;

  • 委托→模型:委托通过模型的setData()方法提交修改,模型验证数据后触发信号通知视图。

这种机制使得Qt MVC的组件间依赖更小,代码更简洁,尤其适合GUI应用的事件驱动特性。

3. 定制灵活性:Qt MVC的“委托”支持更细粒度的UI定制

传统MVC中,控制器的职责是“协调”,不涉及数据项的具体渲染与编辑,因此定制灵活性有限。而Qt MVC的委托允许开发者对单个数据项进行精细定制:

  • 渲染定制:通过重写paint()方法,自定义单元格的绘制逻辑(如用进度条显示任务进度、用颜色标记状态);

  • 编辑定制:通过重写createEditor()方法,为不同数据项创建不同的编辑控件(如日期列用QCalendarWidget、数字列用QSpinBox);

  • 验证定制:通过重写setModelData()方法,对用户输入进行实时验证(如限制输入为正整数、邮箱格式)。

例如,在Qt中,若需让表格的“价格”列只能输入数字,可通过自定义委托重写createEditor()方法,返回QLineEdit并设置正则表达式验证,确保用户输入符合要求。

4. 适用场景:Qt MVC更适配“数据密集型”GUI应用

传统MVC适用于Web应用(如Spring MVC、Django),其中控制器负责处理HTTP请求、协调模型与视图。而Qt MVC(Model/View/Delegate)更适配桌面GUI应用(如数据库管理工具、配置文件编辑器、实时监控仪表盘),其“视图+委托”的结构更适合处理大量数据的可视化与交互

  • 数据密集型场景:如数据库应用中,QSqlTableModel模型可绑定QTableView视图,委托可自定义单元格的编辑方式(如外键列用下拉框),提升数据录入效率;

  • 实时交互场景:如实时监控仪表盘,视图可实时显示模型中的数据变化(如温度、压力),委托可处理用户的“报警确认”等交互操作。

三、总结:Qt MVC是传统MVC的“GUI适配版”

Qt MVC(Model/View/Delegate)并未脱离传统MVC的核心思想,而是通过合并视图与控制器引入委托的方式,优化了GUI应用的交互体验定制灵活性。其本质是:

  • 保留传统MVC的“数据与界面分离”:模型负责数据,视图负责展示;

  • 简化控制器职责:将控制器的“交互路由”功能融入视图,通过信号槽实现松耦合;

  • 增强数据项定制:通过委托支持更细粒度的数据项渲染与编辑,适配GUI应用的复杂需求。

对于开发者而言,Qt MVC的优势在于代码简洁(无需独立控制器)、定制灵活(委托支持精细调整)、交互高效(信号槽机制实时响应),尤其适合开发数据密集型的桌面GUI应用。

如何设计Qt MVC的模型?

设计Qt MVC的模型(Model)时,核心目标是高效管理数据并通过标准接口与视图(View)通信,同时支持数据变化的通知。Qt提供了QAbstractItemModel及其特化类(如QAbstractListModelQAbstractTableModel)作为基类,开发者需根据数据结构选择合适的基类,并实现关键虚函数。以下是具体设计步骤与实践要点:

一、明确数据结构与需求

模型的设计需紧密贴合数据的实际结构业务需求。常见的数据结构有三种:

  • 列表(List):一维数据(如待办事项列表);

  • 表格(Table):二维数据(如Excel表格、数据库表);

  • 树形(Tree):层级结构(如文件目录、组织架构)。

同时需明确:

  • 是否需要支持数据编辑?

  • 是否需要自定义数据展示(如颜色、图标)?

  • 数据量大小(是否需要优化性能)?

二、选择合适的模型基类

Qt提供了多层级的抽象基类,根据数据结构选择可简化开发:

基类 适用场景 需实现的虚函数
QAbstractItemModel 通用树形结构(最灵活) index(), parent(), rowCount(), columnCount(), data(), headerData()
QAbstractListModel 一维列表(简化版) rowCount(), data(), headerData()(部分函数已实现)
QAbstractTableModel 二维表格(简化版) rowCount(), columnCount(), data(), headerData()(部分函数已实现)

建议:优先使用特化类(如QAbstractTableModel),除非数据是复杂树形结构。

三、实现核心虚函数

无论选择哪个基类,都需要实现以下核心函数来定义数据的行为:

1. 数据量与结构:rowCount()columnCount()index()parent()

  • rowCount(const QModelIndex &parent = QModelIndex()) const

    返回父节点下的子项数量。对于列表/表格(无层级),parent无效,直接返回总行数;对于树形结构,需根据parent的行号计算子节点数。

    示例(表格模型):返回固定行数(如return m_data.size();)。

  • columnCount(const QModelIndex &parent = QModelIndex()) const

    返回父节点下的列数。表格/列表通常返回固定列数(如return 3;);树形结构的根节点列数可能与其他节点不同。

  • QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const

    生成指定行、列、父节点的QModelIndex(模型的唯一标识)。树形结构中,parent非空时表示子节点;列表/表格中parent通常无效(返回根节点的子项)。

  • QModelIndex parent(const QModelIndex &child) const

    返回子节点的父节点索引。列表/表格中所有节点的父节点是无效索引(QModelIndex());树形结构需根据child的内部指针找到父节点。

2. 数据访问:data()headerData()

  • QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const

    核心函数,返回指定索引、指定角色的数据。role决定数据的用途:

    • Qt::DisplayRole:视图默认显示的文本;

    • Qt::EditRole:编辑时使用的原始数据;

    • 自定义角色(如Qt::UserRole):存储额外数据(如图标路径、颜色值)。

      示例

    QVariant MyTableModel::data(const QModelIndex &index, int role) const {
        if (!index.isValid()) return QVariant();
        if (role == Qt::DisplayRole || role == Qt::EditRole) {
            return m_data[index.row()][index.column()]; // 返回表格数据
        } else if (role == Qt::TextAlignmentRole) {
            return Qt::AlignCenter; // 文本居中对齐
        }
        return QVariant();
    }
    
  • QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const

    返回表头/列头/行头的数据(如表格的列标题“姓名”“年龄”)。orientationQt::Horizontal(列头)或Qt::Vertical(行头)。

3. 编辑支持:setData()flags()

若模型需要支持用户编辑数据(如双击单元格修改),需实现以下函数:

  • bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)

    处理用户输入的数据修改。验证value的合法性(如数字范围、字符串长度),若合法则更新内部数据,并发出dataChanged()信号通知视图。

    示例

    bool MyTableModel::setData(const QModelIndex &index, const QVariant &value, int role) {
        if (!index.isValid() || role != Qt::EditRole) return false;
        int row = index.row();
        int col = index.column();
        if (col == 1 && value.toInt() < 0) { // 年龄不能为负数
            return false;
        }
        m_data[row][col] = value; // 更新数据
        emit dataChanged(index, index, {role}); // 通知视图更新
        return true;
    }
    
  • Qt::ItemFlags flags(const QModelIndex &index) const

    返回项目的行为标志(如是否可编辑、可选中)。通过Qt::ItemIsEditable启用编辑。

    示例

    Qt::ItemFlags MyTableModel::flags(const QModelIndex &index) const {
        Qt::ItemFlags defaultFlags = QAbstractTableModel::flags(index);
        return defaultFlags | Qt::ItemIsEditable; // 所有单元格可编辑
    }
    

四、数据变化的通知机制

模型的数据变化时,需通过信号通知关联的视图自动更新。Qt模型提供了以下常用信号:

  • dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)

    [topLeft, bottomRight]范围内的数据变化时触发(如修改单个单元格用index, index)。

  • rowsInserted(const QModelIndex &parent, int start, int end)

    插入新行时触发(如添加一行数据)。

  • rowsRemoved(const QModelIndex &parent, int start, int end)

    删除行时触发。

  • layoutChanged()

    数据结构大幅变化时触发(如排序、过滤),强制视图重新加载所有数据。

五、自定义与扩展

1. 自定义数据角色

通过Qt::UserRole及更高值定义自定义角色,存储额外数据(如图标、提示信息):

// data()中处理自定义角色
if (role == Qt::UserRole) {
    return m_icons[index.row()]; // 返回图标路径
}

// 视图或委托中通过data(index, Qt::UserRole)获取

2. 支持排序与过滤

可通过继承QSortFilterProxyModel实现排序和过滤,无需修改原模型:

QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(myModel); // 关联原模型
proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); // 不区分大小写排序
ui->tableView->setModel(proxyModel); // 视图绑定代理模型

3. 性能优化

  • 对于大数据量,避免在data()中执行耗时操作(如数据库查询),可缓存数据;

  • 树形结构中,index()parent()应快速计算(如用哈希表存储父节点指针);

  • 批量修改数据时,使用beginInsertRows()endInsertRows()包裹,避免多次发射信号。

六、示例:一个简单的表格模型

以下是一个继承QAbstractTableModel的表格模型实现,管理学生成绩数据:

#include <QAbstractTableModel>
#include <QVector>
#include <QStringList>

class StudentScoreModel : public QAbstractTableModel {
    Q_OBJECT
public:
    explicit StudentScoreModel(QObject *parent = nullptr) : QAbstractTableModel(parent) {
        // 初始化表头
        m_headers << "姓名" << "数学" << "语文";
        // 初始化数据
        m_data = {
            {"张三", 90, 85},
            {"李四", 88, 92},
            {"王五", 95, 89}
        };
    }

    // 必须实现的虚函数
    int rowCount(const QModelIndex &parent = QModelIndex()) const override {
        Q_UNUSED(parent);
        return m_data.size();
    }

    int columnCount(const QModelIndex &parent = QModelIndex()) const override {
        Q_UNUSED(parent);
        return m_headers.size();
    }

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
        if (!index.isValid() || index.row() >= m_data.size()) return QVariant();
        if (role == Qt::DisplayRole || role == Qt::EditRole) {
            return m_data[index.row()][index.column()];
        } else if (role == Qt::TextAlignmentRole) {
            return Qt::AlignCenter;
        }
        return QVariant();
    }

    QVariant headerData(int section, Qt::Orientation orientation, int role) const override {
        if (role != Qt::DisplayRole || orientation != Qt::Horizontal) 
            return QAbstractTableModel::headerData(section, orientation, role);
        return m_headers[section];
    }

    // 支持编辑
    bool setData(const QModelIndex &index, const QVariant &value, int role) override {
        if (!index.isValid() || role != Qt::EditRole) return false;
        int row = index.row();
        int col = index.column();
        if (col == 1 || col == 2) { // 数学/语文成绩
            bool ok;
            int score = value.toInt(&ok);
            if (!ok || score < 0 || score > 100) return false; // 验证分数范围
        }
        m_data[row][col] = value;
        emit dataChanged(index, index, {role});
        return true;
    }

    Qt::ItemFlags flags(const QModelIndex &index) const override {
        return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
    }

private:
    QVector<QVector<QVariant>> m_data; // 存储表格数据(行×列)
    QStringList m_headers;             // 表头
};

总结

设计Qt MVC模型的关键是:

  1. 根据数据结构选择合适的基类(如QAbstractTableModel);

  2. 正确实现rowCount()columnCount()data()等核心虚函数;

  3. 通过setData()flags()支持编辑;

  4. 利用信号(如dataChanged())通知视图更新;

  5. 结合自定义角色、代理模型等扩展功能。

通过以上步骤,可设计出高效、灵活、易维护的Qt模型,适配各种数据展示与交互需求。

 

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐