第八章:高级控件——QTableWidget、QTreeWidget、QListWidget、QTabWidget、QStackedWidget、QDockWidget
高级控件这块,说实话是Qt里最实用的部分之一。我刚开始做项目时,总觉得基础控件够用了,直到接手一个数据管理工具——嗯,那才明白什么叫「没有高级控件寸步难行」。今天咱们就把这几个重量级选手挨个捋一遍。
8.1 QTableWidget:表格数据展示利器
QTableWidget,说白了就是给用户看二维数据的。你想想看,Excel那种效果,在Qt里用这个控件就能实现。
核心特点:
- 基于行和列的二维数据展示
- 支持单元格编辑、排序、选择
- 表头可自定义,支持多级表头
- 单元格内可嵌入其他控件(如QComboBox、QCheckBox)
我个人习惯,在创建表格前先设置好列数和表头。这样后面填充数据时思路清晰。
// 创建表格
QTableWidget *table = new QTableWidget(this);
table->setColumnCount(4);
table->setHorizontalHeaderLabels({"姓名", "年龄", "部门", "状态"});
// 设置行数
table->setRowCount(10);
// 填充数据
for (int row = 0; row < 10; ++row) {
table->setItem(row, 0, new QTableWidgetItem(QString("员工%1").arg(row + 1)));
table->setItem(row, 1, new QTableWidgetItem(QString::number(25 + row)));
table->setItem(row, 2, new QTableWidgetItem("研发部"));
// 嵌入复选框
QTableWidgetItem *checkItem = new QTableWidgetItem();
checkItem->setCheckState(Qt::Unchecked);
table->setItem(row, 3, checkItem);
}
小技巧:设置setAlternatingRowColors(true)可以让奇偶行颜色交替,视觉上舒服很多。我在做报表工具时,用户反馈说这样看数据不容易串行。
8.2 QTreeWidget:树形结构的不二之选
QTreeWidget适合展示层级关系。比如文件系统、组织架构、分类目录。为什么说它好用?因为它自带展开/折叠功能,你只需要关心数据怎么挂上去。
QTreeWidget *tree = new QTreeWidget(this);
tree->setHeaderLabels({"名称", "类型", "大小"});
// 创建根节点
QTreeWidgetItem *root = new QTreeWidgetItem(tree);
root->setText(0, "项目文件");
root->setText(1, "文件夹");
// 添加子节点
QTreeWidgetItem *child = new QTreeWidgetItem(root);
child->setText(0, "main.cpp");
child->setText(1, "源文件");
child->setText(2, "2.3 KB");
// 再嵌套一层
QTreeWidgetItem *subChild = new QTreeWidgetItem(child);
subChild->setText(0, "utils.h");
subChild->setText(1, "头文件");
subChild->setText(2, "1.1 KB");
tree->expandAll(); // 展开所有节点
我曾经在项目里用QTreeWidget做权限管理,每个节点绑定一个权限ID。用户勾选父节点时,自动勾选所有子节点——这个逻辑用itemChanged信号配合递归就能搞定。
注意:QTreeWidget的节点数量如果超过几千个,性能会明显下降。这时候建议改用QTreeView配合自定义模型。我踩过这个坑,加载一万个节点时界面卡了3秒。
8.3 QListWidget:轻量级列表展示
QListWidget适合展示一维列表数据。它比QTableWidget轻量,比QComboBox展示内容更丰富。你可以往列表项里加图标、加文字、甚至加自定义widget。
QListWidget *list = new QListWidget(this);
// 添加带图标的项
QListWidgetItem *item1 = new QListWidgetItem(QIcon(":/icons/file.png"), "文档1.txt");
list->addItem(item1);
// 添加可勾选项
QListWidgetItem *item2 = new QListWidgetItem("任务2");
item2->setCheckState(Qt::Unchecked);
list->addItem(item2);
// 设置选择模式
list->setSelectionMode(QAbstractItemView::ExtendedSelection);
// 响应双击
connect(list, &QListWidget::itemDoubleClicked, [=](QListWidgetItem *item) {
qDebug() << "双击了:" << item->text();
});
适用场景:文件列表、聊天记录、待办事项、历史记录。说白了就是「一行一个条目」的场景。
8.4 QTabWidget与QStackedWidget:页面切换双雄
这两个控件经常搭配使用。QTabWidget提供标签页切换,QStackedWidget提供页面堆叠。你想想看,一个设置对话框,左边是标签,右边是内容——这就是它们的经典组合。
8.4.1 QTabWidget:标签页切换
QTabWidget *tabWidget = new QTabWidget(this);
// 创建页面
QWidget *page1 = new QWidget();
QWidget *page2 = new QWidget();
QWidget *page3 = new QWidget();
// 添加标签页
tabWidget->addTab(page1, "基本设置");
tabWidget->addTab(page2, "高级设置");
tabWidget->addTab(page3, "关于");
// 设置当前页
tabWidget->setCurrentIndex(0);
// 关闭按钮
tabWidget->setTabsClosable(true);
connect(tabWidget, &QTabWidget::tabCloseRequested, [=](int index) {
tabWidget->removeTab(index);
});
8.4.2 QStackedWidget:页面堆叠管理
QStackedWidget *stack = new QStackedWidget(this);
// 添加页面
QWidget *loginPage = new QWidget();
QWidget *mainPage = new QWidget();
QWidget *settingPage = new QWidget();
stack->addWidget(loginPage); // index 0
stack->addWidget(mainPage); // index 1
stack->addWidget(settingPage);// index 2
// 切换到主页面
stack->setCurrentIndex(1);
// 或者通过指针切换
stack->setCurrentWidget(mainPage);
我的经验:QStackedWidget配合QListWidget做侧边导航,效果比QTabWidget更灵活。左侧列表点击,右侧切换页面,这种模式在管理后台很常见。
8.5 QDockWidget:可停靠窗口
QDockWidget是Qt里最灵活的布局控件之一。它可以让用户自由拖动、停靠、悬浮。像VS Code、Qt Creator的侧边栏,就是用这个实现的。
// 创建停靠窗口
QDockWidget *dock = new QDockWidget("文件浏览器", this);
dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
// 设置内容
QListWidget *fileList = new QListWidget();
fileList->addItem("main.cpp");
fileList->addItem("mainwindow.h");
fileList->addItem("mainwindow.cpp");
dock->setWidget(fileList);
// 添加到主窗口
addDockWidget(Qt::LeftDockWidgetArea, dock);
// 设置特性
dock->setFeatures(QDockWidget::DockWidgetMovable |
QDockWidget::DockWidgetClosable |
QDockWidget::DockWidgetFloatable);
避坑指南:我曾经在项目中允许用户随意拖动dock,结果布局乱成一团。后来加了setAllowedAreas限制,只允许左右停靠,问题就解决了。另外,记得给dock设置一个最小尺寸,否则拖到太小会很难看。
8.6 综合应用:打造一个简易IDE界面
咱们把上面这些控件组合起来,做一个简易的代码编辑器界面。你想想看,左边是文件树,中间是代码编辑区(用QStackedWidget管理多个文件),下面是输出面板(用QDockWidget实现)。
// 主窗口构造函数
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
// 1. 左侧文件树
QDockWidget *fileDock = new QDockWidget("项目文件", this);
QTreeWidget *fileTree = new QTreeWidget();
fileTree->setHeaderLabel("文件");
fileDock->setWidget(fileTree);
addDockWidget(Qt::LeftDockWidgetArea, fileDock);
// 2. 中央标签页(多文件编辑)
QTabWidget *editorTabs = new QTabWidget();
editorTabs->setTabsClosable(true);
setCentralWidget(editorTabs);
// 3. 底部输出面板
QDockWidget *outputDock = new QDockWidget("输出", this);
QListWidget *outputList = new QListWidget();
outputDock->setWidget(outputList);
addDockWidget(Qt::BottomDockWidgetArea, outputDock);
// 4. 右侧属性面板(用QStackedWidget)
QDockWidget *propDock = new QDockWidget("属性", this);
QStackedWidget *propStack = new QStackedWidget();
propStack->addWidget(new QWidget()); // 空属性页
propStack->addWidget(createFilePropPage()); // 文件属性页
propDock->setWidget(propStack);
addDockWidget(Qt::RightDockWidgetArea, propDock);
}
核心逻辑:点击文件树中的文件 → 在QTabWidget中打开或切换到对应标签 → 标签切换时更新右侧属性面板(QStackedWidget切换页面)。这个模式在Qt Creator、VS Code、Eclipse中都能看到影子。
8.7 知识体系结构图
8.8 总结与建议
这几个控件,说白了就是Qt界面开发的「半壁江山」。我个人建议你按这个顺序学习:
- 先掌握QListWidget——最简单,容易上手
- 再学QTableWidget——二维数据展示,项目里最常用
- 然后QTreeWidget——树形结构,理解父子节点关系
- 接着QTabWidget+QStackedWidget——页面切换,组合使用
- 最后QDockWidget——可停靠窗口,提升用户体验
我的心得:不要试图一次性记住所有API。先理解每个控件的「核心用途」,用到什么功能再去查文档。Qt的官方文档写得不错,配合Qt Creator的自动补全,开发效率很高。
嗯,高级控件这块就讲到这里。记住一点:控件是工具,怎么组合使用才是真本事。多动手写几个小项目,自然就熟练了。
公众号:蓝海资料掘金营,微信deep3321