一、基本概念
1.1 什么是 QStackedWidget
QStackedWidget 是 Qt 中的一个容器控件,它可以包含多个子控件(页面),但一次只显示其中一个。类似于一叠卡片,只有最上面的卡片可见。
1.2 主要特点
-
多个页面共享同一显示区域
-
一次只显示一个页面
-
可通过索引或指针切换页面
-
常用于实现标签页、向导界面等
二、Qt6 中的语法和 API
2.1 基本 API
cpp
#include <QStackedWidget>
// 创建
QStackedWidget *stackedWidget = new QStackedWidget(parent);
// 添加页面
int index = stackedWidget->addWidget(widget);
int index = stackedWidget->insertWidget(index, widget);
// 切换页面
stackedWidget->setCurrentIndex(index); // 通过索引
stackedWidget->setCurrentWidget(widget); // 通过指针
// 获取信息
int currentIndex = stackedWidget->currentIndex();
QWidget *currentWidget = stackedWidget->currentWidget();
int count = stackedWidget->count();
QWidget *widget = stackedWidget->widget(index);
// 移除页面
stackedWidget->removeWidget(widget);
2.2 信号
cpp
// 当前页面改变时发射
void currentChanged(int index);
void widgetRemoved(int index);
三、案例
QStackWidget核心
cpp
// 创建堆叠布局
m_stackedWidget = new QStackedWidget(this);
QWidget *gridPage = new QWidget();
// 创建详情页
m_detailpage = new detailpage(this);
// 添加到堆叠窗口
m_stackedWidget->addWidget(gridPage);
m_stackedWidget->addWidget(m_detailpage);
这里我们可以看到两个页面都添加到堆叠布局中:
我们可以通过 m_stackedWidget->setCurrentIndex(index);的方式进行切换:
例如上面的那个当index=0时就是gridPage页面;当index=1时就是detailpage。
整体代码
mianwindow.h
cpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "detailpage.h"
#include <QMainWindow>
#include <QStackedWidget>
#include <QGridLayout>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void onProductClicked(int index);
void onBackFromDetail();
private:
Ui::MainWindow *ui;
struct ProductInfo
{
QString title;
QString image;
QString details;
};
void setupUI();
void initProducts();
bool eventFilter(QObject *obj, QEvent *event);
QVector<ProductInfo> m_products;
QStackedWidget *m_stackedWidget;
QGridLayout *m_gridLayout;
detailpage *m_detailpage;
};
#endif // MAINWINDOW_H
mainwindow.cpp
cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QLabel>
#include <QMouseEvent>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
setupUI();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setupUI()
{
resize(800, 600);
// 创建堆叠布局
m_stackedWidget = new QStackedWidget(this);
QWidget *gridPage = new QWidget();
m_gridLayout = new QGridLayout(gridPage);
m_gridLayout->setSpacing(10);
// 创建详情页
m_detailpage = new detailpage(this);
// 添加到堆叠窗口
m_stackedWidget->addWidget(gridPage);
m_stackedWidget->addWidget(m_detailpage);
setCentralWidget(m_stackedWidget);
// 初始化产品数据
initProducts();
// 创建产品卡片
for (int i = 0; i < m_products.size(); ++i) {
const ProductInfo &product = m_products[i];
// 创建卡片容器
QWidget *card = new QWidget();
card->setFixedSize(200, 200);
card->setProperty("productIndex", i);
card->installEventFilter(this);
// 卡片内部布局
QVBoxLayout *cardLayout = new QVBoxLayout(card);
// 产品图标
QLabel *iconLabel = new QLabel(product.image);
iconLabel->setAlignment(Qt::AlignCenter);
cardLayout->addWidget(iconLabel);
// 产品标题
QLabel *titleLabel = new QLabel(product.title);
titleLabel->setAlignment(Qt::AlignCenter);
cardLayout->addWidget(titleLabel);
// 添加到网格布局
int row = i / 3;
int col = i % 3;
m_gridLayout->addWidget(card, row, col, Qt::AlignCenter);
}
// 连接信号
connect(m_detailpage, &detailpage::backRequest, this, &MainWindow::onBackFromDetail);
}
void MainWindow::initProducts()
{
m_products = {
{
"火灾预防",
"🔥",
"火灾预防是消防安全的第一道防线。本产品包含家庭用电安全规范、厨房用火注意事项等。"
}
};
}
void MainWindow::onProductClicked(int index)
{
if (index >= 0 && index < m_products.size()) {
const ProductInfo &product = m_products[index];
m_detailpage->setProductInfo(product.title, product.image, product.details);
m_stackedWidget->setCurrentIndex(1);
}
}
void MainWindow::onBackFromDetail()
{
m_stackedWidget->setCurrentIndex(0);
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton) {
QWidget *card = qobject_cast<QWidget*>(obj);
if (card) {
int index = card->property("productIndex").toInt();
onProductClicked(index);
return true;
}
}
}
return QWidget::eventFilter(obj, event);
}
detailpage.h
cpp
#ifndef DETAILPAGE_H
#define DETAILPAGE_H
#include <QWidget>
#include <QTextEdit>
#include <QPushButton>
class detailpage : public QWidget
{
Q_OBJECT
public:
explicit detailpage(QWidget *parent = nullptr);
void setProductInfo(const QString &title, const QString &image, const QString &details);
signals:
void backRequest();
private slots:
void onBackClicked();
private:
QTextEdit *m_detailsText;
QPushButton *m_backButton;
};
#endif // DETAILPAGE_H
detailpage.cpp
cpp
#include "detailpage.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
detailpage::detailpage(QWidget *parent)
: QWidget{parent}
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
// 返回按钮
m_backButton = new QPushButton("返回");
connect(m_backButton, &QPushButton::clicked, this, &detailpage::onBackClicked);
// 详细信息显示
m_detailsText = new QTextEdit();
m_detailsText->setReadOnly(true);
mainLayout->addWidget(m_backButton);
mainLayout->addWidget(m_detailsText);
}
void detailpage::setProductInfo(const QString &title, const QString &image, const QString &details)
{
QString formattedDetails = QString("<h2>%1</h2><p>%2</p>").arg(title, details);
m_detailsText->setHtml(formattedDetails);
}
void detailpage::onBackClicked()
{
emit backRequest();
}
四、效果
第一个界面

点击图标后跳转到第二个界面
