第八章:高级控件——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 知识体系结构图

Qt高级控件知识体系 高级控件 QTableWidget QTreeWidget QListWidget QTabWidget QStackedWidget QDockWidget 典型应用场景 数据管理 | 文件浏览器 | 设置对话框 | IDE界面 | 报表工具

8.8 总结与建议

这几个控件,说白了就是Qt界面开发的「半壁江山」。我个人建议你按这个顺序学习:

  1. 先掌握QListWidget——最简单,容易上手
  2. 再学QTableWidget——二维数据展示,项目里最常用
  3. 然后QTreeWidget——树形结构,理解父子节点关系
  4. 接着QTabWidget+QStackedWidget——页面切换,组合使用
  5. 最后QDockWidget——可停靠窗口,提升用户体验

我的心得:不要试图一次性记住所有API。先理解每个控件的「核心用途」,用到什么功能再去查文档。Qt的官方文档写得不错,配合Qt Creator的自动补全,开发效率很高。

嗯,高级控件这块就讲到这里。记住一点:控件是工具,怎么组合使用才是真本事。多动手写几个小项目,自然就熟练了。


公众号:蓝海资料掘金营,微信deep3321