前言
上一篇大致过完窗体,这篇聊下界面的切换,毕竟不管哪个应用一般都不会是单页面。
界面切换
界面切换在我个人用的过程中,有几个方式可以分享下。
- Widget 的显示隐藏,在上一篇聊 Widget 的时候应该还有印象是啥效果
- TabWidget,通过选项卡的方式切换界面
- StackedWidget,类似选项卡,不过没有 tab 按钮,推荐是使用这种。
我们来看下几种方式的实现过程以及效果。
准备工作:新建工程选择 MainWindow,然后新建三个 Widget 作为单页。
主窗体 ui 设置如下图所示。

首先实例化对应的 Widget 这个就不多说了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include "Widget1.h" #include "Widget2.h" #include "Widget3.h"
public: QtDemo(QWidget *parent = Q_NULLPTR);
private: void init();
private: Ui::QtDemoClass ui;
Widget1* m_widget1; Widget2* m_widget2; Widget3* m_widget3;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| QtDemo::QtDemo(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); init(); }
void QtDemo::init() { m_widget1 = new Widget1(ui.groupBox); m_widget2 = new Widget2(ui.groupBox); m_widget3 = new Widget3(ui.groupBox);
m_widget2->hide(); m_widget3->hide(); }
|
运行之后可以自己看下效果,也可以自己做个测试,如果那两个没有隐藏,效果是啥样(最好给三个界面的 label 位置调整下,可以看的更明显),当然这个不是说明三个 widget 是同层,实际还是不同的层,只是每个 Widget 的内容比较单一,如果设置了背景色就能看出来还是会存在遮挡的,不设置图层的话,一般都是按照 new 的先后顺序,先放的肯定是在最下面。
我们来设置下按钮事件来做切换,这里捎带聊下 qt 的事件机制,也就是信号、槽。
信号、槽
信号槽的模式类似于事件委托,也有点儿像观察者模式,即一方发出信号,由已注册的另一方根据信号做对应事件的响应与处理。
1 2 3 4 5 6 7 8 9 10 11 12 13
| static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);
static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method, Qt::ConnectionType type = Qt::AutoConnection);
inline QMetaObject::Connection connect(const QObject *sender, const char *signal, const char *member, Qt::ConnectionType type = Qt::AutoConnection) const;
static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot, Qt::ConnectionType type = Qt::AutoConnection)
|
通过这几个方法可以实现事件的绑定,发送方->接收方(通过哪种信号,以及接收方处理的方法)。
信号槽的特点如下:
- 一个信号可以绑定多个槽
- 多个信号可以绑定一个槽
- 一个信号可以关联到另一个信号
- 一个信号可以关联到多个信号
回归到我们第一个实现方式的编码来,在头文件新加几个按钮点击的方法(注意 btn3 的事件没有在 slots 标签下)。
1 2 3 4 5 6 7 8 9
| public: QtDemo(QWidget *parent = Q_NULLPTR);
void btnWidget3Clicked();
public slots: void btnWidget1Clicked(); void btnWidget2Clicked();
|
在 cpp 中实现对应的方法事件,同样留意 btn3 的写法(qt5 以上可以这样使用)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
void QtDemo::btnWidget1Clicked() { m_widget1->show(); m_widget2->hide(); m_widget3->hide(); }
void QtDemo::btnWidget2Clicked() { m_widget1->hide(); m_widget2->show(); m_widget3->hide(); }
void QtDemo::btnWidget3Clicked() { m_widget1->hide(); m_widget2->hide(); m_widget3->show(); }
void QtDemo::setConnection() { connect(ui.btnWidget1, SIGNAL(clicked()), this, SLOT(btnWidget1Clicked())); connect(ui.btnWidget2, SIGNAL(clicked()), this, SLOT(btnWidget2Clicked())); connect(ui.btnWidget3, &QPushButton::clicked, this, &QtDemo::btnWidget3Clicked); }
|
运行之后点击按钮,就实现了界面的切换。
这个比较简单,我们可以直接通过界面直接添加 Tab Widget 组件来直接切换界面,这里我拿 widget1 做了调整。

用过选项卡的肯定都清楚,本身选项卡内就是一个个 Widget,也就相当于是一个个单独的界面。
我们也可以通过代码动态去添加已经写好的界面。
1 2
| m_widget3 = new Widget3(); ui->tabWidget->addTab(m_widget3, QStringLiteral("界面3"));
|
这个堆小部件的大致用法与TabWidget类似,不过它没有选项卡的直接切换,需要通过按钮事件来自己去设置显示哪个索引下的 widget。
修改对应方法如下,每次 addWidget 相当于添加一个 Page,可以理解为存放界面的数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| void QtDemo::btnWidget1Clicked() { ui.stackedWidget->setCurrentIndex(0); }
void QtDemo::btnWidget2Clicked() { ui.stackedWidget->setCurrentIndex(1); }
void QtDemo::btnWidget3Clicked() { ui.stackedWidget->setCurrentIndex(2); }
void QtDemo::init() { m_widget1 = new Widget1(); m_widget2 = new Widget2(); m_widget3 = new Widget3();
ui.stackedWidget->addWidget(m_widget1); ui.stackedWidget->addWidget(m_widget2); ui.stackedWidget->addWidget(m_widget3);
setConnection(); }
|
小结
界面切换暂时就聊这么多,这仅是个人使用过程中总结的,可能不是太合适,不过效果跟预期还是一样的,建议使用 StackedWidget 来实现界面的切换,当然 TabWidget 去了 tab 跟这个显示的就基本一样了,这种相对来说维护方便些,切换只需要设置对应的索引显示就行,同第一种比较还是便利许多(毕竟第一种如果界面多了,那每次显示隐藏都要写一堆)。