跳到主要内容

容器控件

容器控件用于组织和分组其他控件,使界面结构更清晰、更易于管理。

QGroupBox(分组框)

带有标题的边框容器,用于将相关控件分组。

#include <QGroupBox>
#include <QVBoxLayout>
#include <QRadioButton>

// 创建分组框
QGroupBox *groupBox = new QGroupBox("用户设置", this);

// 在分组框中添加控件
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(new QRadioButton("选项 A"));
layout->addWidget(new QRadioButton("选项 B"));
layout->addWidget(new QRadioButton("选项 C"));
groupBox->setLayout(layout);

// 设置对齐方式
groupBox->setAlignment(Qt::AlignLeft); // 标题左对齐

// 启用/禁用整个分组
groupBox->setEnabled(false);

// 复选框分组框(可勾选)
QGroupBox *checkableGroup = new QGroupBox("高级选项", this);
checkableGroup->setCheckable(true);
checkableGroup->setChecked(false); // 默认未选中

connect(checkableGroup, &QGroupBox::toggled, this, [=](bool checked) {
qDebug() << "分组框状态:" << checked;
});

QTabWidget(标签页)

通过标签页组织多个页面,节省界面空间。

#include <QTabWidget>
#include <QWidget>

// 创建标签页控件
QTabWidget *tabWidget = new QTabWidget(this);

// 创建页面
QWidget *page1 = new QWidget();
QVBoxLayout *layout1 = new QVBoxLayout(page1);
layout1->addWidget(new QLabel("这是第一页的内容"));
layout1->addWidget(new QPushButton("按钮1"));

QWidget *page2 = new QWidget();
QVBoxLayout *layout2 = new QVBoxLayout(page2);
layout2->addWidget(new QLabel("这是第二页的内容"));
layout2->addWidget(new QLineEdit());

QWidget *page3 = new QWidget();
// ... 设置第三页

// 添加标签页
tabWidget->addTab(page1, "基本信息");
tabWidget->addTab(page2, QIcon(":/icons/settings.png"), "设置");
tabWidget->addTab(page3, "关于");

// 设置当前页
tabWidget->setCurrentIndex(0);

// 标签位置
tabWidget->setTabPosition(QTabWidget::North); // 顶部(默认)
// 其他:South, West, East

// 标签形状
tabWidget->setTabShape(QTabWidget::Rounded); // 圆角(默认)
// QTabWidget::Triangular - 三角形

// 标签可关闭
tabWidget->setTabsClosable(true);
connect(tabWidget, &QTabWidget::tabCloseRequested, this, [=](int index) {
tabWidget->removeTab(index);
});

// 标签可移动
tabWidget->setMovable(true);

// 信号
connect(tabWidget, &QTabWidget::currentChanged, this, [=](int index) {
qDebug() << "切换到标签页:" << index;
});

// 插入标签页到指定位置
tabWidget->insertTab(1, newPage, "新页面");

// 禁用某个标签
tabWidget->setTabEnabled(2, false);

QStackedWidget(堆叠窗口)

管理多个页面,但只显示一个,常用于向导或切换视图。

#include <QStackedWidget>

// 创建堆叠窗口
QStackedWidget *stackedWidget = new QStackedWidget(this);

// 添加页面
QWidget *page1 = new QWidget();
QWidget *page2 = new QWidget();
QWidget *page3 = new QWidget();

stackedWidget->addWidget(page1); // 返回索引 0
stackedWidget->addWidget(page2); // 返回索引 1
stackedWidget->addWidget(page3); // 返回索引 2

// 切换页面
stackedWidget->setCurrentIndex(1); // 通过索引
stackedWidget->setCurrentWidget(page2); // 通过指针

// 获取当前页
int currentIndex = stackedWidget->currentIndex();
QWidget *currentPage = stackedWidget->currentWidget();

// 与按钮配合实现页面切换
QPushButton *nextBtn = new QPushButton("下一步", this);
connect(nextBtn, &QPushButton::clicked, this, [=]() {
int next = stackedWidget->currentIndex() + 1;
if (next < stackedWidget->count()) {
stackedWidget->setCurrentIndex(next);
}
});

QPushButton *prevBtn = new QPushButton("上一步", this);
connect(prevBtn, &QPushButton::clicked, this, [=]() {
int prev = stackedWidget->currentIndex() - 1;
if (prev >= 0) {
stackedWidget->setCurrentIndex(prev);
}
});

QScrollArea(滚动区域)

当内容超出显示区域时提供滚动条。

#include <QScrollArea>
#include <QWidget>
#include <QVBoxLayout>

// 创建滚动区域
QScrollArea *scrollArea = new QScrollArea(this);

// 创建内容窗口
QWidget *contentWidget = new QWidget();
QVBoxLayout *layout = new QVBoxLayout(contentWidget);

// 添加大量内容
for (int i = 0; i < 50; i++) {
layout->addWidget(new QPushButton(QString("按钮 %1").arg(i)));
}

// 设置内容
scrollArea->setWidget(contentWidget);

// 关键设置:让内容窗口自适应
scrollArea->setWidgetResizable(true);

// 滚动条策略
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); // 按需显示
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); // 总是显示
// 其他选项:ScrollBarAlwaysOff(总是隐藏)

// 程序化滚动
scrollArea->verticalScrollBar()->setValue(100); // 滚动到指定位置

// 获取当前滚动位置
int hValue = scrollArea->horizontalScrollBar()->value();
int vValue = scrollArea->verticalScrollBar()->value();

QSplitter(分割器)

允许用户拖动调整子控件的大小。

#include <QSplitter>
#include <QTextEdit>
#include <QListWidget>

// 创建水平分割器
QSplitter *splitter = new QSplitter(Qt::Horizontal, this);

// 添加子控件
QListWidget *listWidget = new QListWidget();
listWidget->addItems({"项目1", "项目2", "项目3"});

QTextEdit *textEdit = new QTextEdit();
textEdit->setPlainText("右侧编辑区域");

QTreeWidget *treeWidget = new QTreeWidget();

splitter->addWidget(listWidget);
splitter->addWidget(textEdit);
splitter->addWidget(treeWidget);

// 设置初始比例
splitter->setSizes(QList<int>() << 200 << 400 << 200);

// 设置拉伸因子
splitter->setStretchFactor(0, 1); // 第一个控件拉伸因子1
splitter->setStretchFactor(1, 3); // 第二个控件拉伸因子3(占更多空间)

// 设置最小尺寸
splitter->setMinimumSize(600, 400);

// 保存/恢复分割状态
QSettings settings;
settings.setValue("splitterState", splitter->saveState());
splitter->restoreState(settings.value("splitterState").toByteArray());

// 嵌套分割器
QSplitter *vSplitter = new QSplitter(Qt::Vertical);
vSplitter->addWidget(topWidget);
vSplitter->addWidget(splitter); // 水平分割器作为子控件

QFrame(框架)

带边框的基础容器,可用于视觉分隔。

#include <QFrame>

// 创建框架
QFrame *frame = new QFrame(this);

// 设置边框样式
frame->setFrameShape(QFrame::StyledPanel); // 样式面板
frame->setFrameShadow(QFrame::Raised); // 凸起效果
// 形状选项:NoFrame, Box, Panel, StyledPanel, HLine, VLine
// 阴影选项:Plain, Raised, Sunken

// 设置线宽
frame->setLineWidth(2);
frame->setMidLineWidth(1);

// 常用作水平/垂直分隔线
QFrame *hLine = new QFrame(this);
hLine->setFrameShape(QFrame::HLine);
hLine->setFrameShadow(QFrame::Sunken);

QFrame *vLine = new QFrame(this);
vLine->setFrameShape(QFrame::VLine);
vLine->setFrameShadow(QFrame::Sunken);

// 配合布局使用
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(section1);
layout->addWidget(hLine); // 分隔线
layout->addWidget(section2);

QDockWidget(停靠窗口)

可停靠、浮动、关闭的面板,常用于 IDE 风格的界面。

#include <QDockWidget>
#include <QMainWindow>
#include <QTextEdit>

// 需要在 QMainWindow 中使用
QMainWindow *mainWindow = new QMainWindow();

// 创建停靠窗口
QDockWidget *dock1 = new QDockWidget("文件浏览器", mainWindow);
QTreeWidget *tree = new QTreeWidget();
dock1->setWidget(tree);

QDockWidget *dock2 = new QDockWidget("属性", mainWindow);
QTableWidget *table = new QTableWidget();
dock2->setWidget(table);

// 添加到主窗口
mainWindow->addDockWidget(Qt::LeftDockWidgetArea, dock1);
mainWindow->addDockWidget(Qt::RightDockWidgetArea, dock2);

// 停靠区域选项
// Qt::LeftDockWidgetArea, Qt::RightDockWidgetArea
// Qt::TopDockWidgetArea, Qt::BottomDockWidgetArea
// Qt::AllDockWidgetAreas

// 设置特性
dock1->setFeatures(QDockWidget::DockWidgetMovable |
QDockWidget::DockWidgetFloatable);
// 特性选项:
// DockWidgetClosable - 可关闭
// DockWidgetMovable - 可移动
// DockWidgetFloatable - 可浮动
// DockWidgetVerticalTitleBar - 垂直标题栏
// AllDockWidgetFeatures - 所有特性
// NoDockWidgetFeatures - 无特性

// 信号
connect(dock1, &QDockWidget::visibilityChanged, this, [=](bool visible) {
qDebug() << "停靠窗口可见性:" << visible;
});

connect(dock1, &QDockWidget::topLevelChanged, this, [=](bool floating) {
qDebug() << "是否浮动:" << floating;
});

// 分割停靠区域
mainWindow->splitDockWidget(dock1, dock2, Qt::Horizontal);

// 标签化停靠(Qt 5.6+)
mainWindow->tabifyDockWidget(dock1, dock2);

QMdiArea(多文档区域)

实现多文档界面(MDI),同时管理多个子窗口。

#include <QMdiArea>
#include <QMdiSubWindow>
#include <QTextEdit>

// 创建 MDI 区域
QMdiArea *mdiArea = new QMdiArea(this);

// 创建子窗口
QMdiSubWindow *subWindow1 = new QMdiSubWindow();
subWindow1->setWidget(new QTextEdit());
subWindow1->setWindowTitle("文档 1");
mdiArea->addSubWindow(subWindow1);

QMdiSubWindow *subWindow2 = new QMdiSubWindow();
subWindow2->setWidget(new QTextEdit());
subWindow2->setWindowTitle("文档 2");
mdiArea->addSubWindow(subWindow2);

// 显示子窗口
subWindow1->show();
subWindow2->show();

// 视图模式
mdiArea->setViewMode(QMdiArea::SubWindowView); // 子窗口视图(默认)
// mdiArea->setViewMode(QMdiArea::TabbedView); // 标签页视图

// 排列子窗口
mdiArea->tileSubWindows(); // 平铺
mdiArea->cascadeSubWindows(); // 层叠

// 激活窗口
mdiArea->setActiveSubWindow(subWindow1);

// 信号
connect(mdiArea, &QMdiArea::subWindowActivated, this, [=](QMdiSubWindow *window) {
if (window) {
qDebug() << "激活窗口:" << window->windowTitle();
}
});

// 关闭所有子窗口
mdiArea->closeAllSubWindows();

完整示例:复杂界面布局

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
{
setWindowTitle("复杂布局示例");
resize(1000, 700);

// 创建中央部件 - 分割器
QSplitter *mainSplitter = new QSplitter(Qt::Horizontal, this);
setCentralWidget(mainSplitter);

// 左侧 - 文件浏览器
QDockWidget *fileDock = new QDockWidget("文件", this);
QTreeWidget *fileTree = new QTreeWidget();
fileTree->setHeaderLabel("文件列表");
fileDock->setWidget(fileTree);
addDockWidget(Qt::LeftDockWidgetArea, fileDock);

// 中间 - 标签页
QTabWidget *tabWidget = new QTabWidget();

// 第一页 - 表单
QWidget *formPage = new QWidget();
QFormLayout *formLayout = new QFormLayout(formPage);
formLayout->addRow("姓名:", new QLineEdit());
formLayout->addRow("年龄:", new QSpinBox());
formLayout->addRow("备注:", new QTextEdit());
tabWidget->addTab(formPage, "基本信息");

// 第二页 - 设置
QWidget *settingsPage = new QWidget();
QVBoxLayout *settingsLayout = new QVBoxLayout(settingsPage);
QGroupBox *group1 = new QGroupBox("显示设置");
QVBoxLayout *group1Layout = new QVBoxLayout(group1);
group1Layout->addWidget(new QCheckBox("显示工具栏"));
group1Layout->addWidget(new QCheckBox("显示状态栏"));
settingsLayout->addWidget(group1);
settingsLayout->addStretch();
tabWidget->addTab(settingsPage, "设置");

// 第三页 - 带滚动区域
QScrollArea *scrollArea = new QScrollArea();
QWidget *scrollContent = new QWidget();
QVBoxLayout *scrollLayout = new QVBoxLayout(scrollContent);
for (int i = 0; i < 20; i++) {
scrollLayout->addWidget(new QPushButton(QString("按钮 %1").arg(i)));
}
scrollArea->setWidget(scrollContent);
scrollArea->setWidgetResizable(true);
tabWidget->addTab(scrollArea, "长列表");

mainSplitter->addWidget(tabWidget);

// 右侧 - 属性面板
QDockWidget *propDock = new QDockWidget("属性", this);
QTableWidget *propTable = new QTableWidget(5, 2);
propTable->setHorizontalHeaderLabels({"属性", "值"});
propDock->setWidget(propTable);
addDockWidget(Qt::RightDockWidgetArea, propDock);

// 底部 - 输出面板
QDockWidget *outputDock = new QDockWidget("输出", this);
QTextEdit *outputEdit = new QTextEdit();
outputEdit->setReadOnly(true);
outputDock->setWidget(outputEdit);
addDockWidget(Qt::BottomDockWidgetArea, outputDock);

// 设置分割比例
mainSplitter->setSizes(QList<int>() << 200 << 600 << 200);

// 创建菜单
QMenu *viewMenu = menuBar()->addMenu("视图");
viewMenu->addAction(fileDock->toggleViewAction());
viewMenu->addAction(propDock->toggleViewAction());
viewMenu->addAction(outputDock->toggleViewAction());
}
};

布局选择指南

容器适用场景特点
QGroupBox相关控件分组带标题边框,视觉分组
QTabWidget多页面内容标签切换,节省空间
QStackedWidget向导、步骤流程程序化切换页面
QScrollArea内容超出视口自动滚动条
QSplitter可调比例区域用户可拖动调整
QDockWidgetIDE 风格面板可停靠、浮动
QMdiArea多文档编辑同时管理多个子窗口

下一步

继续学习 高级控件,掌握表格、树形控件等复杂控件的使用。