Qt 视图窗口核心分类
Qt 视图窗口分为 Item-Based(基于项)和 Model-Based(基于模型)两类,核心区别如下:
| 类型 | 核心特点 | 典型控件 |
|---|---|---|
| Item-Based | 直接操作控件的「项」(Item)实现数据更新,数据与视图耦合度高 | QListWidget、QTableWidget、QTreeWidget |
| Model-Based | 数据存储在「模型」中,视图仅负责展示,数据与视图解耦,支持实时更新、数据共享 | QListView、QTableView、QTreeView |
基础模型类说明(Model-Based 核心)
所有模型类均继承自 QAbstractItemModel,以下是常用模型的核心作用:
- QAbstractListModel:抽象列表模型,定义列表数据的基础接口(需子类化实现具体逻辑)。
- QAbstractTableModel:抽象表格模型,定义表格数据的基础接口(需子类化实现具体逻辑)。
- QAbstractProxyModel:抽象代理模型,用于对已有模型做数据转换(如排序、过滤、合并)。
- QConcatenateTablesProxyModel:代理模型,将多个表格模型按行拼接为一个模型。
- QDirModel:已废弃(Qt5+ 推荐 QFileSystemModel),用于访问文件系统目录结构。
- QFileSystemModel:文件系统模型,实时获取本地文件/目录信息(支持动态更新)。
- QStandardItemModel:通用标准模型,无需子类化即可快速实现列表/表格/树形数据存储(简化 Model-Based 开发)。
Item-Based 核心控件
QListWidget(列表控件)

核心概念
以列表形式展示项(文本、图标、自定义控件),直接操作 QListWidgetItem 实现数据管理,适用于简单列表场景。
基础操作:添加内容
添加纯文本项
/**
* 添加单个文本项到列表末尾
* @brief addItem
* @param label 要显示的文本内容
* @return void 无返回值
*/
ui->listWidget->addItem("Hello Widget");
/**
* 批量添加文本项到列表末尾
* @brief addItems
* @param labels 文本列表(QStringList)
* @return void 无返回值
*/
QStringList strList;
strList << "123" << "456" << "789" << "000";
ui->listWidget->addItems(strList);

添加带图标的项
/**
* 构造带图标和文本的列表项
* @brief QListWidgetItem 构造函数
* @param icon 项的图标(QIcon),支持本地图片路径/资源文件
* @param text 项的文本内容
* @param parent 所属的QListWidget(可选)
* @return QListWidgetItem* 构造的项对象(需手动管理内存)
*/
QListWidgetItem *item = new QListWidgetItem(QIcon("./img/123.jpg"), "Hello Icon");
/**
* 添加自定义项到列表末尾
* @brief addItem
* @param item 已构造的QListWidgetItem对象
* @return void 无返回值
*/
ui->listWidget->addItem(item);

添加自定义控件/窗口

// 1. 构造自定义窗口(如自定义的Friend窗口)
Friend *newFriend = new Friend();
// 2. 构造空白列表项(仅作为载体)
QListWidgetItem *newItem = new QListWidgetItem();
ui->listWidget->addItem(newItem);
/**
* 设置列表项的尺寸(匹配自定义窗口大小)
* @brief setSizeHint
* @param size 目标尺寸(QSize),一般取自定义窗口的推荐尺寸
* @return void 无返回值
*/
newItem->setSizeHint(newFriend->sizeHint());
/**
* 给列表项绑定自定义控件
* @brief setItemWidget
* @param item 目标列表项
* @param widget 要显示的自定义控件/窗口
* @return void 无返回值
*/
ui->listWidget->setItemWidget(newItem, newFriend);
信号与槽(核心交互)
| 信号 | 触发场景 | 参数说明 |
|---|---|---|
| currentRowChanged(int) | 当前选中行发生变化时 | currentRow:新选中行的索引(从0开始) |
| currentTextChanged(QString) | 当前选中项的文本发生变化时 | currentText:新选中项的文本内容 |
| itemClicked(QListWidgetItem*) | 单击某一项时 | item:被单击的项对象 |
| itemDoubleClicked(QListWidgetItem*) | 双击某一项时 | item:被双击的项对象 |
| itemSelectionChanged() | 选中项发生变化时(无参数) | - |
示例1:获取选中行/文本

/**
* 选中行变化时触发的槽函数
* @brief on_listWidget_currentRowChanged
* @param currentRow 新选中行的索引(-1表示无选中)
* @return void 无返回值
*/
void MainWindow::on_listWidget_currentRowChanged(int currentRow)
{
qDebug() << "当前选中行:" << currentRow;
}

/**
* 选中项文本变化时触发的槽函数
* @brief on_listWidget_currentTextChanged
* @param currentText 新选中项的文本
* @return void 无返回值
*/
void MainWindow::on_listWidget_currentTextChanged(const QString ¤tText)
{
qDebug() << "当前选中文本:" << currentText;
ui->groupBox->setTitle(currentText); // 同步更新分组框标题
}

示例2:双击删除项
/**
* 双击项时删除该项目
* @brief on_listWidget_itemDoubleClicked
* @param item 被双击的项对象
* @return void 无返回值
* @note removeItemWidget仅移除项内的控件,不删除项;takeItem删除项并返回对象(需手动释放内存)
*/
void MainWindow::on_listWidget_itemDoubleClicked(QListWidgetItem *item)
{
int row = ui->listWidget->row(item); // 获取项的行索引
/**
* 删除指定行的项
* @brief takeItem
* @param row 要删除的行索引
* @return QListWidgetItem* 被删除的项对象(需手动delete释放,否则内存泄漏)
*/
QListWidgetItem *delItem = ui->listWidget->takeItem(row);
delete delItem; // 释放内存
}

常用接口(QListWidget/QListWidgetItem)
QListWidget 核心接口
/**
* 在指定行插入文本项
* @brief insertItem
* @param row 插入位置(索引)
* @param text 文本内容
* @return void 无返回值
*/
ui->listWidget->insertItem(1, "插入到第2行的项");
/**
* 获取指定行的项对象
* @brief item
* @param row 目标行索引
* @return QListWidgetItem* 目标行的项(NULL表示行不存在)
*/
QListWidgetItem *targetItem = ui->listWidget->item(0);
/**
* 获取当前选中项
* @brief currentItem
* @return QListWidgetItem* 当前选中项(NULL表示无选中)
*/
QListWidgetItem *curItem = ui->listWidget->currentItem();
QListWidgetItem 核心接口
/**
* 设置项的文本颜色
* @brief setTextColor
* @param color 目标颜色(QColor)
* @return void 无返回值
*/
item->setTextColor(Qt::red);
/**
* 设置项的复选框状态
* @brief setCheckState
* @param state 复选状态(Qt::Unchecked/Checked/PartiallyChecked)
* @return void 无返回值
*/
item->setCheckState(Qt::Checked);
/**
* 设置项的提示文本(鼠标悬浮时显示)
* @brief setToolTip
* @param tip 提示文本
* @return void 无返回值
*/
item->setToolTip("这是一个带图标的项");
QTableWidget(表格控件)
核心概念
基于项的表格控件,直接操作 QTableWidgetItem 管理单元格数据,支持嵌入自定义控件,适用于简单表格场景。
基础操作:添加内容
初始化表格行列
/**
* 设置表格行数
* @brief setRowCount
* @param rows 行数(正整数)
* @return void 无返回值
*/
ui->tableWidget->setRowCount(5);
/**
* 设置表格列数
* @brief setColumnCount
* @param columns 列数(正整数)
* @return void 无返回值
*/
ui->tableWidget->setColumnCount(3);
/**
* 设置水平表头标签
* @brief setHorizontalHeaderLabels
* @param labels 表头文本列表(QStringList)
* @return void 无返回值
*/
QStringList headerLabels;
headerLabels << "姓名" << "年龄" << "性别";
ui->tableWidget->setHorizontalHeaderLabels(headerLabels);
添加文本单元格
/**
* 构造表格单元格项
* @brief QTableWidgetItem 构造函数
* @param text 单元格文本
* @return QTableWidgetItem* 单元格项对象
*/
QTableWidgetItem *newItem = new QTableWidgetItem("张三");
/**
* 设置指定单元格的项
* @brief setItem
* @param row 行索引(从0开始)
* @param column 列索引(从0开始)
* @param item 单元格项对象
* @return void 无返回值
*/
ui->tableWidget->setItem(0, 0, newItem);
添加自定义控件(如按钮)
/**
* 构造自定义按钮
* @brief QPushButton 构造函数
* @param text 按钮文本
* @param parent 父控件(可选)
* @return QPushButton* 按钮对象
*/
QPushButton *btn = new QPushButton("点击", this);
connect(btn, &QPushButton::clicked, []() {
qDebug() << "表格内按钮被点击";
});
/**
* 设置指定单元格的自定义控件
* @brief setCellWidget
* @param row 行索引
* @param column 列索引
* @param widget 要嵌入的控件对象
* @return void 无返回值
*/
ui->tableWidget->setCellWidget(0, 2, btn);

表格布局优化
/**
* 设置表头拉伸模式(最后一列填充剩余空间)
* @brief setStretchLastSection
* @param stretch 是否拉伸(true/false)
* @return void 无返回值
*/
ui->tableWidget->horizontalHeader()->setStretchLastSection(true);
/**
* 设置所有列平均拉伸
* @brief setSectionResizeMode
* @param mode 拉伸模式(QHeaderView::Stretch 表示平均拉伸)
* @return void 无返回值
*/
ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
核心信号
| 信号 | 触发场景 | 参数说明 |
|---|---|---|
| cellClicked(int, int) | 单击单元格时 | row:行索引,column:列索引 |
| cellDoubleClicked(int, int) | 双击单元格时 | row:行索引,column:列索引 |
| currentCellChanged(int, int, int, int) | 当前选中单元格变化时 | 当前行、当前列、之前行、之前列 |
QTreeWidget(树形控件)
核心概念
基于项的树形控件,通过 QTreeWidgetItem 构建层级结构,支持多列树形展示,适用于简单树形数据场景。
基础操作:构建树形结构
/**
* 设置树形控件列数
* @brief setColumnCount
* @param columns 列数(默认1列)
* @return void 无返回值
*/
ui->treeWidget->setColumnCount(1);
ui->treeWidget->setHeaderLabel("树形结构示例");
/**
* 构造根节点
* @brief QTreeWidgetItem 构造函数
* @param parent 父节点(NULL表示根节点,也可传treeWidget)
* @return QTreeWidgetItem* 节点对象
*/
QTreeWidgetItem *rootItem = new QTreeWidgetItem(ui->treeWidget);
rootItem->setText(0, "根节点"); // 设置第0列文本
/**
* 构造子节点(父节点为rootItem)
* @brief QTreeWidgetItem 构造函数
* @param parent 父节点对象
* @return QTreeWidgetItem* 子节点对象
*/
QTreeWidgetItem *childItem1 = new QTreeWidgetItem(rootItem);
childItem1->setText(0, "一级子节点");
/**
* 构造孙子节点(父节点为childItem1)
*/
QTreeWidgetItem *childItem2 = new QTreeWidgetItem(childItem1);
childItem2->setText(0, "二级子节点");
/*公共槽函数*/
rootItem->expand(); // 展开根节点

常用接口
/**
* 设置是否显示根节点的展开/折叠图标
* @brief setRootIsDecorated
* @param decorate 是否显示(true显示,false隐藏)
* @return void 无返回值
*/
ui->treeWidget->setRootIsDecorated(false);
/**
* 设置是否启用排序
* @brief setSortingEnabled
* @param enable 是否启用(true启用,false禁用)
* @return void 无返回值
*/
ui->treeWidget->setSortingEnabled(true);
Model-Based 核心控件:QTreeView
核心概念
基于模型的树形视图,必须配合模型使用(数据存储在模型,视图仅展示),支持实时更新、数据共享,适用于复杂/动态树形数据场景(如文件系统)。
核心接口
/**
* 设置视图的数据源模型
* @brief setModel
* @param model 继承自QAbstractItemModel的模型对象
* @return void 无返回值
*/
void setModel(QAbstractItemModel *model);
/**
* 展开指定索引的节点
* @brief expand
* @param index 模型中的索引(QModelIndex)
* @return void 无返回值
*/
void expand(const QModelIndex &index);
/**
* 设置视图的根索引(仅展示模型中该索引下的子数据)
* @brief setRootIndex
* @param index 模型中的根索引
* @return void 无返回值
*/
void setRootIndex(const QModelIndex &index);
示例:展示文件系统

/**
* 构造文件系统模型
* @brief QFileSystemModel 构造函数
* @param parent 父对象(可选)
* @return QFileSystemModel* 模型对象
*/
QFileSystemModel *fileModel = new QFileSystemModel(this);
/**
* 设置模型监控的根路径
* @brief setRootPath
* @param path 本地路径(如"D:/")
* @return QString 标准化后的路径
*/
fileModel->setRootPath("D:/");
// 给QTreeView设置模型
ui->treeView->setModel(fileModel);
/**
* 获取指定路径在模型中的索引
* @brief index
* @param path 目标路径
* @return QModelIndex 路径对应的模型索引
*/
QModelIndex targetIndex = fileModel->index("D:/APP");
// 设置视图仅展示"D:/APP"下的文件/目录
ui->treeView->setRootIndex(targetIndex);
// 隐藏不需要的列(QFileSystemModel默认列:名称、大小、类型、修改时间)
ui->treeView->hideColumn(1);
ui->treeView->hideColumn(2);
ui->treeView->hideColumn(3);

Qt 多界面组件
MDI 窗口(Multiple Document Interface多文档界面)
核心概念
在一个主窗口内显示多个子窗口,子窗口可层叠/平铺,适用于同时编辑多个文档的场景(如多文本编辑器)。核心类:
QMdiArea:容纳子窗口的容器(需设置为QMainWindow的中央控件)。QMdiSubWindow:MDI子窗口(可嵌入任意QWidget作为内容)。
示例代码
#include <QApplication>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QTextEdit>
#include <QMainWindow>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// 1. 构造MDI容器
/**
* 构造MDI容器
* @brief QMdiArea 构造函数
* @param parent 父对象(可选)
* @return QMdiArea* MDI容器对象
*/
QMdiArea *mdiArea = new QMdiArea;
// 2. 构造第一个子窗口
QMdiSubWindow *subWin1 = new QMdiSubWindow;
QTextEdit *edit1 = new QTextEdit;
/**
* 设置子窗口的内容控件
* @brief setWidget
* @param widget 要嵌入的内容控件
* @return void 无返回值
*/
subWin1->setWidget(edit1);
subWin1->setWindowTitle("文档1"); // 设置子窗口标题
// 3. 构造第二个子窗口
QMdiSubWindow *subWin2 = new QMdiSubWindow;
QTextEdit *edit2 = new QTextEdit;
subWin2->setWidget(edit2);
subWin2->setWindowTitle("文档2");
// 4. 添加子窗口到MDI容器
/**
* 添加子窗口到MDI容器
* @brief addSubWindow
* @param subWindow MDI子窗口对象
* @return QMdiSubWindow* 添加后的子窗口对象(与入参一致)
*/
mdiArea->addSubWindow(subWin1);
mdiArea->addSubWindow(subWin2);
// 5. 设置主窗口
QMainWindow mainWin;
mainWin.setCentralWidget(mdiArea); // MDI容器作为中央控件
mainWin.setWindowTitle("MDI多文档示例");
mainWin.resize(800, 600);
// 6. 子窗口布局(平铺)
/**
* 平铺所有子窗口
* @brief tileSubWindows
* @return void 无返回值
*/
mdiArea->tileSubWindows();
mainWin.show();
return app.exec();
}

常用接口
/**
* 层叠排列所有子窗口
* @brief cascadeSubWindows
* @return void 无返回值
*/
mdiArea->cascadeSubWindows();
/**
* 设置活动子窗口
* @brief setActiveSubWindow
* @param subWindow 目标子窗口(NULL表示取消激活)
* @return void 无返回值
*/
mdiArea->setActiveSubWindow(subWin1);
Dock 窗口(停靠窗口)
核心概念
可浮动、可停靠在主窗口边缘的窗口,适用于工具栏、属性面板等场景。核心类:
QDockWidget:停靠窗口容器(需嵌入QMainWindow)。QMainWindow:提供停靠区域(左/右/上/下)。
示例代码
#include <QApplication>
#include <QMainWindow>
#include <QDockWidget>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// 1. 构造主窗口
QMainWindow mainWin;
mainWin.setWindowTitle("Dock停靠窗口示例");
mainWin.resize(800, 600);
// 2. 构造Dock窗口
/**
* 构造停靠窗口
* @brief QDockWidget 构造函数
* @param title 停靠窗口标题
* @param parent 父对象(可选)
* @return QDockWidget* 停靠窗口对象
*/
QDockWidget *dockWidget = new QDockWidget("工具栏", &mainWin);
// 3. 构造Dock内容(按钮)
QPushButton *btn = new QPushButton("停靠窗口按钮", dockWidget);
dockWidget->setWidget(btn); // 设置Dock内容
// 4. 设置Dock允许的停靠区域
/**
* 设置允许的停靠区域
* @brief setAllowedAreas
* @param areas 停靠区域(Qt::LeftDockWidgetArea/Right/Top/Bottom/AllDockWidgetAreas)
* @return void 无返回值
*/
dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
// 5. 将Dock添加到主窗口左侧
/**
* 添加Dock窗口到主窗口
* @brief addDockWidget
* @param area 初始停靠区域
* @param dockwidget 停靠窗口对象
* @return void 无返回值
*/
mainWin.addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
mainWin.show();
return app.exec();
}

QTabWidget(标签窗口)
核心概念
在一个窗口内通过标签切换多个页面,适用于分类展示不同内容(如多标签浏览器、配置面板)。
示例代码
#include <QApplication>
#include <QTabWidget>
#include <QTextEdit>
#include <QIcon>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// 1. 构造标签窗口
QTabWidget *tabWidget = new QTabWidget;
tabWidget->setWindowTitle("标签窗口示例");
tabWidget->resize(600, 400);
// 2. 添加标签页1(文本编辑器)
/**
* 添加标签页
* @brief addTab
* @param page 标签页内容控件
* @param label 标签文本
* @return int 标签页索引(从0开始)
*/
QTextEdit *edit1 = new QTextEdit;
int tab1Index = tabWidget->addTab(edit1, "标签1");
/**
* 设置标签页图标
* @brief setTabIcon
* @param index 标签页索引
* @param icon 图标(QIcon)
* @return void 无返回值
*/
tabWidget->setTabIcon(tab1Index, QIcon(":/images/tab1.png"));
// 3. 添加标签页2
QTextEdit *edit2 = new QTextEdit;
tabWidget->addTab(edit2, "标签2");
// 4. 添加标签页3(禁用)
QTextEdit *edit3 = new QTextEdit;
int tab3Index = tabWidget->addTab(edit3, "标签3");
/**
* 设置标签页是否可用
* @brief setTabEnabled
* @param index 标签页索引
* @param enabled 是否可用(true可用,false禁用)
* @return void 无返回值
*/
tabWidget->setTabEnabled(tab3Index, false);
// 5. 设置当前选中标签页
/**
* 设置当前选中标签页
* @brief setCurrentIndex
* @param index 标签页索引
* @return void 无返回值
*/
tabWidget->setCurrentIndex(1); // 选中第二个标签页
// 6. 开启标签页可关闭(显示×按钮)
/**
* 设置标签页是否可关闭
* @brief setTabsClosable
* @param closable 是否可关闭(true显示关闭按钮)
* @return void 无返回值
*/
tabWidget->setTabsClosable(true);
tabWidget->show();
return app.exec();
}

常用接口
/**
* 移除指定标签页
* @brief removeTab
* @param index 标签页索引
* @return void 无返回值
* @note 仅移除标签页,内容控件需手动释放内存
*/
tabWidget->removeTab(0);
/**
* 获取标签页数量
* @brief count
* @return int 标签页数量(正整数)
*/
int tabCount = tabWidget->count();
/**
* 设置标签页可拖动
* @brief setMovable
* @param movable 是否可拖动(true允许拖动调整顺序)
* @return void 无返回值
*/
tabWidget->setMovable(true);
关键注意事项
- 内存管理:Item-Based 控件中,
takeItem/takeRow仅移除项,需手动delete释放对象;Model-Based 控件中,模型负责数据内存管理,视图仅展示。 - 性能优化:大量数据场景优先使用 Model-Based 控件(如 QTableView 替代 QTableWidget),避免 Item-Based 控件的性能瓶颈。
- 自定义控件嵌入:QListWidget/QTableWidget 嵌入自定义控件时,需通过
setSizeHint匹配项/单元格尺寸,否则控件可能显示不全。 - 信号与槽参数:QListWidget/QTableWidget 的信号参数(如
currentRowChanged)中,索引从 0 开始,-1 表示无选中项。
783

被折叠的 条评论
为什么被折叠?



