Qt中Item Views(Model-Based)与Item Widgets(Item-Based)的深度解析

一、核心概念与区别

  1. Item Views(Model-Based)

    • 定义‌:基于模型-视图架构(Model/View Architecture),通过分离数据存储(Model)与界面展示(View)实现灵活的数据管理。典型控件如 QTreeViewQListViewQTableView
    • 特点‌:
      • 需手动创建数据模型(如 QStandardItemModel),数据操作通过模型完成‌
      • 支持大规模数据的高效处理(如百万级数据无卡顿)‌
      • 适用于复杂数据逻辑(如动态增删、多视图同步)‌
    • 典型控件‌:QListViewQTreeViewQTableView
  2. Item Widgets(Item-Based)

    • 定义‌:基于项的便利类(如 QTreeWidgetQListWidget),内部默认集成数据模型,简化开发流程‌
    • 特点‌:
      • 直接操作项(如 QTreeWidgetItem),无需显式定义模型‌
      • 适合小型数据集(如配置项、静态列表)
      • 代码简单但扩展性较差‌
    • 典型控件‌:QListWidgetQTreeWidgetQTableWidget

二、详细解释:

1. Item Widgets(Item-Based)

第一个控件:QListView

        QListView 是 Qt 框架中用于展示列表数据的核心控件,基于‌模型-视图-委托(Model-View-Delegate)架构‌,支持灵活的数据管理和交互操作。
QListView常用操作与交互
  1. 数据操作

    • 添加项‌:通过模型 appendRow() 或 insertRow() 插入数据‌。
    • 删除项‌:调用模型 removeRow() 移除指定行‌。
    • 自定义委托‌:继承 QStyledItemDelegate 实现自定义绘制和交互逻辑‌。
  2. 信号与事件

    • 点击事件‌:clickeddoubleClicked 等信号传递 QModelIndex 实现交互响应‌。
    • 右键菜单‌:通过 setContextMenuPolicy 和 CustomContextMenu 信号实现上下文菜单‌。
  3. 选择与导航

    • 选中项‌:setCurrentIndex() 设置默认选中行,currentRowChanged 信号监听行变化‌
    • 多选模式‌:通过 setSelectionMode() 设置 ExtendedSelection 支持多选‌。

示例项目结构与代码:

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QListView>
#include <QStringListModel>
#include <QMessageBox>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
    QListView* listview1;       // 创建QListView对象

private slots:
    void SlotClickedFunc(const QModelIndex &index);
};
#endif // WIDGET_H

‌widget.h

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    resize(450, 250);

    listview1 = new QListView(this);    // 创建QListView对象
    listview1->setGeometry(20, 20, 240, 160);   // 设置控件显示位置和控件大小
    QStringList qlist;
    qlist.append("运动员:篮球、足球");
    qlist.append("娱乐类:看电影,写小说、听音乐");
    qlist.append("游戏类:五子棋、扑克牌、中国象棋");
    qlist.append("旅游类:国内旅游,国外旅游");

    // 用数据列表创建数据显示模型进行实现
    QStringListModel *listmodel = new QStringListModel(qlist);  // 将列表添加进去
    listview1->setModel(listmodel);

    // 让信号和槽函数进行连接
    connect(listview1, SIGNAL(clicked(const QModelIndex)), this, SLOT(SlotClickedFunc(const QModelIndex)));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::SlotClickedFunc(const QModelIndex &index){
    QMessageBox::information(NULL, "兴趣爱好", "你选择的类型为:\n" + index.data().toString());     // 设置文本
}

实现效果:

第二个控件:QTreeView

一、QTreeView概述

QTreeView 是 Qt 框架中用于展示‌树形结构数据‌的核心控件,基于‌模型-视图架构‌(Model/View Architecture),通过数据模型(Model)与视图(View)解耦实现灵活的数据管理‌。

  • 适用场景‌:文件系统目录、组织结构图、多层级配置项等层次化数据展示‌。
  • 核心优势‌:支持动态数据更新、多视图同步、自定义渲染等复杂操作‌。
二、常用操作与交互
  1. 数据操作

    • 添加项‌:通过模型 appendRow() 或 insertRow() 插入数据‌。
    • 删除项‌:调用模型 removeRow() 移除指定行‌。
    • 自定义委托‌:继承 QStyledItemDelegate 实现自定义绘制和交互逻辑‌。
  2. 信号与事件

    • 点击事件‌:clickeddoubleClicked 等信号传递 QModelIndex 实现交互响应‌。
    • 右键菜单‌:通过 setContextMenuPolicy 和 CustomContextMenu 信号实现上下文菜单‌。
  3. 选择与导航

    • 选中项‌:setCurrentIndex() 设置默认选中行,currentRowChanged 信号监听行变化‌。
    • 多选模式‌:通过 setSelectionMode() 设置 ExtendedSelection 支持多选‌。
三、示例代码(首先需要再ui文件中添加一个QTreeView类):

项目目录如下:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QStandardItemModel>
#include <QStandardItem>
#include <QStringList>
#include <QList>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

public:
    void InitTreeViewFunc();    // 初始化树控件视图
    QStandardItemModel *sItemModel;     // 项目模型变量

};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    InitTreeViewFunc(); // 在构造函数调用树视图控件
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::InitTreeViewFunc() // 初始化树视图函数
{
    // 1.构造model
    sItemModel = new QStandardItemModel(ui->treeView);  // 创建树形视图
    sItemModel->setHorizontalHeaderLabels(QStringList()<<QStringLiteral("编号")<<QStringLiteral("初中部|高中部"));
    // 创建第一个一级节点,将它加入到sItemModel
    QList<QStandardItem*> item11;   // 数据列表
    QStandardItem *item1 = new QStandardItem(QString::number(1));
    QStandardItem *item2 = new QStandardItem("初中部");
    item11.append(item1);
    item11.append(item2);
    sItemModel->appendRow(item11);  // 添加一级节点

    // 二级节点,添加到第一个一级节点
    QList<QStandardItem*> item112;
    QStandardItem *item1121 = new QStandardItem(QString::number(2));
    QStandardItem *item1122 = new QStandardItem("一年级");     // 这个相当于初中部一年级
    item112.append(item1121);
    item112.append(item1122);
    item1->appendRow(item112);  // 添加一级节点item1中才有效果

    // 三级节点,该三级节点将添加到第一个二级节点
    QList<QStandardItem*> item1231;
    QStandardItem *item12311 = new QStandardItem(QString::number(3));       // 三级节点的标注
    QStandardItem *item12312 = new QStandardItem(QStringLiteral("一班"));     // 初中部一年级一班
    item1231.append(item12311);     // 把这两个加入到三级节点中
    item1231.append(item12312);
    item1121->appendRow(item1231);  // 把三级节点添加到二级节点中的“2”中

    // 第二个三级节点
    QList<QStandardItem*> item1232;
    QStandardItem *item12321 = new QStandardItem(QString::number(3));       // 三级节点的标注
    QStandardItem *item12322 = new QStandardItem(QStringLiteral("二班"));     // 初中部一年级一班
    item1232.append(item12321);     // 把这两个加入到三级节点中
    item1232.append(item12322);
    item1121->appendRow(item1232);  // 把三级节点添加到二级节点中的“2”中




    // 添加一级节点item12进去,这个是第二个一级节点
    QList<QStandardItem*> item12;   // 数据列表
    QStandardItem *item3 = new QStandardItem(QString::number(2));
    QStandardItem *item4 = new QStandardItem("高中部");
    item12.append(item3);
    item12.append(item4);
    sItemModel->appendRow(item12);  // 添加一级节点


    // 2.给QTreeView应用model
    ui->treeView->setModel(sItemModel);
}
实现效果:

2. Item Views(Model-Based)

第一个控件:QListWidget

一、基本概念
  • 功能定位‌:QListWidget是Qt提供的列表控件,继承自QListView,内置了QStandardItemModel模型,简化了列表项的添加和管理‌12。
  • 核心特性‌:
    • 直接管理QListWidgetItem对象,每个项可包含文本、图标、复选框等‌67。
    • 支持单/多选、拖放、排序、自定义样式等交互功能‌37。
  • 特点‌:通过模型管理数据,视图仅负责展示,支持多视图共享同一模型‌。
二、核心用法
  1. 创建与初始化

    QListWidget *listWidget = new QListWidget(this); // 创建实例‌:ml-citation{ref="1,3" data="citationList"}
  2. 添加项

    • 基础文本项‌:
      QListWidgetItem *item = new QListWidgetItem("Item 1"); listWidget->addItem(item); // 直接添加‌:ml-citation{ref="3" data="citationList"}
    • 带图标的项‌:
      QListWidgetItem *item = new QListWidgetItem(QIcon("icon.png"), "Item 1"); listWidget->addItem(item); // 图标+文本‌:ml-citation{ref="5" data="citationList"}
  3. 删除项

    • 通过索引删除:
      listWidget->takeItem(0); // 移除第1项(返回被移除的项)‌:ml-citation{ref="1,4" data="citationList"}
    • 清空所有项:
      listWidget->clear(); // 清空列表‌:ml-citation{ref="5" data="citationList"}


三、交互与事件处理
  1. 信号与槽

    • 点击事件‌:
      connect(listWidget, &QListWidget::itemClicked, [](QListWidgetItem *item) { qDebug() << "选中项:" << item->text(); }); // 单击响应‌:ml-citation{ref="6,7" data="citationList"}
    • 选中项变化‌:
      connect(listWidget, &QListWidget::currentItemChanged, [](QListWidgetItem *current, QListWidgetItem *previous) { if (current) qDebug() << "当前项:" << current->text(); }); // 监听选中变化‌:ml-citation{ref="5,7" data="citationList"}
  2. 右键菜单

    listWidget->setContextMenuPolicy(Qt::CustomContextMenu); connect(listWidget, &QListWidget::customContextMenuRequested, [](const QPoint &pos) { QMenu menu; menu.addAction("删除"); menu.exec(QCursor::pos()); // 弹出右键菜单‌:ml-citation{ref="4,7" data="citationList"} });

QListWidget示例代码:

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QListWidgetItem* qitem = new QListWidgetItem("沁园春.雪--作者:毛泽东");  // 给qlistWidget设置一个标题
    ui->listWidget->addItem(qitem);
    QStringList slist;
    qitem->setTextAlignment(Qt::AlignCenter);       // 让标题中心对齐
    slist << "1.北国风光,千里冰封,万里雪飘。";
    slist << "2.望长城内外,惟余莽莽;大河上下,顿时滔滔。";

    ui->listWidget->addItems(slist);
}

Widget::~Widget()
{
    delete ui;
}

结果:

第二个控件:QTableWidget:

一、基本概念:

QTableWidget‌ 是 Qt 中用于展示和编辑二维表格数据的控件,继承自 QTableView,但内置了默认的数据模型,通过直接操作单元格(QTableWidgetItem)简化开发流程‌。

  • 适用场景‌:中小规模静态数据(如学生信息表、配置项)或需要快速实现表格功能的场景‌。
  • 核心特点‌:
    • 无需手动创建数据模型,直接通过行、列索引操作单元格‌。
    • 支持单元格内容编辑、样式定制及信号交互‌
QTableWidget核心方法详解

1. 设置表格行数与列数
  • 方法‌:
    setRowCount(int rows) / setColumnCount(int cols)
  • 功能‌:
    初始化表格的‌总行数‌和‌总列数‌,用于定义表格的初始结构。
  • 示例‌:
    QTableWidget *table = new QTableWidget; table->setRowCount(5); // 初始5行 table->setColumnCount(3); // 初始3列
  • 注意事项‌:
    • 若后续动态增删行/列,需调用 insertRow() 或 removeRow() 等接口‌。
    • 设置行数后,未填充数据的行默认显示空白单元格‌。

2. 设置水平表头标签
  • 方法‌:
    setHorizontalHeaderLabels(const QStringList &labels)
  • 功能‌:
    为表格的‌‌设置标题,标题数量需与列数一致。
  • 示例‌:
    QStringList headers; headers << "学号" << "姓名" << "成绩"; table->setHorizontalHeaderLabels(headers); // 设置3列标题‌:ml-citation{ref="1,2" data="citationList"}
  • 注意事项‌:
    • 若未设置标题,默认显示空表头‌。
    • 支持通过 horizontalHeader()->setStyleSheet() 自定义表头样式(如背景色、字体)‌。

3. 填充单元格数据
  • 方法‌:
    setItem(int row, int column, QTableWidgetItem *item)
  • 功能‌:
    向指定单元格填充数据(文本、图标、复选框等),需创建 QTableWidgetItem 对象。
  • 示例‌:
    // 创建文本项
    QTableWidgetItem *idItem = new QTableWidgetItem("2023001");
    table->setItem(0, 0, idItem);  // 第0行第0列填充数据‌:ml-citation{ref="1,6" data="citationList"}
    
    // 创建带复选框的项
    QTableWidgetItem *checkItem = new QTableWidgetItem("未完成");
    checkItem->setCheckState(Qt::Unchecked);  // 设置复选框状态‌:ml-citation{ref="1,5" data="citationList"}
    table->setItem(0, 1, checkItem);
    
  • 注意事项‌:
    • QTableWidgetItem 需手动管理内存(建议通过 new 创建并设置父对象)‌。
    • 若单元格未初始化(未调用 setItem()),直接访问可能导致程序崩溃‌。

4. 动态增删行
  • 方法‌:
    insertRow(int row) / removeRow(int row)
  • 功能‌:
    在指定位置插入新行或删除已有行,支持动态调整表格结构。
  • 示例‌:
    // 在第2行插入新行(原第2行及后续行下移)
    table->insertRow(1);  
    table->setItem(1, 0, new QTableWidgetItem("2023002"));  
    
    // 删除第0行(后续行上移)
    table->removeRow(0);  
    
  • 注意事项‌:
    • 插入行时需确保新行索引不超过当前行数范围(否则无效)‌。
    • 删除行后,原行索引后续的行会自动前移‌。

5. 综合应用示例
// 创建表格并初始化
QTableWidget table;
table.setRowCount(3);
table.setColumnCount(2);
table.setHorizontalHeaderLabels({"姓名", "年龄"});

// 填充数据
table.setItem(0, 0, new QTableWidgetItem("张三"));
table.setItem(0, 1, new QTableWidgetItem("25"));
table.setItem(1, 0, new QTableWidgetItem("李四"));
table.setItem(1, 1, new QTableWidgetItem("30"));

// 动态插入行
table.insertRow(2);
table.setItem(2, 0, new QTableWidgetItem("王五"));
table.setItem(2, 1, new QTableWidgetItem("28"));

‌QTableWidget 总结

QTableWidget 的 setRowCount()setColumnCount() 等方法用于定义表格基础结构,setItem() 和动态增删接口实现数据填充与管理。通过合理调用这些方法,可快速构建功能完整的表格界面‌。

第三个控件:QTreeWidget

一、基本概念:

QTreeWidget‌ 是 Qt 中基于项的树形控件,继承自 QTreeView,但内置默认数据模型,通过直接操作节点(QTreeWidgetItem)实现树形结构的快速构建‌。

  • 适用场景‌:静态层级数据展示(如文件目录、组织架构、配置树等)‌。
  • 核心特点‌:
    • 无需手动创建数据模型,直接通过节点对象管理层级关系‌。
    • 支持多列显示、节点展开/折叠、复选框交互及自定义样式‌。

二、核心方法与操作
1. 控件初始化
方法功能说明示例
setColumnCount(int)设置控件显示的列数(默认1列)‌tree->setColumnCount(2);
setHeaderLabels(QStringList)设置表头标题(需与列数一致)‌tree->setHeaderLabels({"名称", "ID"});
2. 节点管理
  • 添加节点‌:
// 添加根节点
QTreeWidgetItem *root = new QTreeWidgetItem(tree);
root->setText(0, "总部");  
tree->addTopLevelItem(root);  // 必须调用此方法显示根节点‌:ml-citation{ref="5,6" data="citationList"}  

// 添加子节点
QTreeWidgetItem *child = new QTreeWidgetItem(root);
child->setText(0, "技术部");
  • 删除节点‌:
delete child;  // 直接释放对象(需确保无其他引用)‌:ml-citation{ref="4" data="citationList"}  
或  
root->removeChild(child);  // 从父节点移除子节点‌:ml-citation{ref="4" data="citationList"}  
3. 数据与属性设置
  • 节点数据存储‌:
child->setData(0, Qt::UserRole, 100);  // 存储自定义数据(如ID)‌:ml-citation{ref="5,6" data="citationList"}  
int id = child->data(0, Qt::UserRole).toInt();  // 读取数据‌:ml-citation{ref="5,6" data="citationList"}  
  • 设置图标与样式‌:
child->setIcon(0, QIcon(":/icon.png"));  // 设置节点图标‌:ml-citation{ref="3,6" data="citationList"}  
child->setBackground(0, QBrush(Qt::yellow));  // 设置背景色‌:ml-citation{ref="6,7" data="citationList"}  

三、高级功能
1. 复选框功能
// 启用复选框
child->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);  
child->setCheckState(0, Qt::Unchecked);  // 初始状态‌:ml-citation{ref="3,4" data="citationList"}  

// 信号处理勾选事件
connect(tree, &QTreeWidget::itemChanged, [](QTreeWidgetItem *item, int col) {
    if (item->checkState(col) == Qt::Checked) {
        qDebug() << "选中节点:" << item->text(0);
    }
});  
2. 动态交互与优化
  • 展开/折叠控制‌:
tree->expandItem(root);  // 展开节点‌:ml-citation{ref="1,3" data="citationList"}  
tree->collapseItem(child);  // 折叠节点‌:ml-citation{ref="1,3" data="citationList"}  
  • 排序功能‌:
tree->setSortingEnabled(true);  // 启用排序‌:ml-citation{ref="8" data="citationList"}  
tree->sortByColumn(0, Qt::AscendingOrder);  // 按首列升序排列‌:ml-citation{ref="8" data="citationList"}  

四、与QTreeView的对比
特性QTreeWidgetQTreeView
开发效率高(直接操作节点,无需模型)‌低(需自定义模型,如 QStandardItemModel)‌
适用场景静态数据(如配置树、小型目录)‌动态数据(如数据库查询结果、大规模文件系统)‌

‌五、注意事项
  1. 性能问题‌:
    • 数据量超过 ‌1000 节点‌ 时,建议改用 QTreeView + 自定义模型‌。
  2. 内存管理‌:
    • 手动删除节点时需确保无父节点引用,否则可能引发内存泄漏‌。
  3. 交互设计‌:
    • 避免同时启用多选模式和复选框,防止用户操作冲突‌。


三、适用场景对比

场景Item WidgetsItem Views
数据规模小型数据(<1000项)‌大规模数据(>10000项)‌
开发复杂度快速实现,代码简单‌需额外模型定义,较复杂‌
扩展性低(数据与界面耦合)‌高(数据与界面分离)‌

四、设计思想与性能分析

  1. 继承关系

    • Item Widgets(如 QTreeWidget)继承自 Item Views(如 QTreeView),属于其便利子类‌。
    • 例如:QTreeWidget 继承 QTreeView,并内置默认模型‌。
  2. 性能差异

    • Item Views 通过模型代理机制优化渲染,减少内存占用;Item Widgets 直接操作项,数据量大时易卡顿‌。

五、最佳实践建议

  1. 选择依据

    • 优先使用 Item Views 处理动态或复杂数据‌。
    • 快速原型开发可选用 Item Widgets‌。

总结

Item Views 与 Item Widgets 是 Qt 中数据展示的两种核心方案。前者以模型驱动为核心,适合高性能场景;后者以项操作为核心,简化开发流程。理解其差异与适用场景,可显著提升 Qt 应用的开发效率与性能表现。个人感觉这两个是差不多的。

写在最后:

我们可以在这里学习C++知识:

https://github.com/0voice

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值