學習筆記第二篇,利用Qt實現選項卡式的頁面,效果如圖1.1-圖1.3所示。程序實現的功能是通過點擊狀態欄實現不同頁面的切換,實際上Qt中自帶有Tab選項卡式的控件,本文利用StackWidge實現類似的頁面切換功能。本文的開發思路以及頁面代碼參考了陸文周主編的《Qt5開發及實例(第3版)》(中國工信出版社)。

圖1.1 基本信息界面

圖1.2 聯系方式界面

圖1.3 詳細資料界面
本文軟件的框架如圖1.4所示,下面從最下層的內容開始介紹。

圖1.4 軟件開發框架
1、底層頁面的構建
最底層的頁面分為三個類,基本信息(BaseInfo)類,聯系方式(Contact)類以及詳細資料(Detail)類,三個類均繼承自QWidget類。
(1)Class BaseInfo
baseinfo.h
#ifndef BASEINFO_H
#define BASEINFO_H
#include <QtCore/qglobal.h>
#if QT_VERSION >= 0x050000
#include <QtWidgets/QWidget>
#else
#include <QtGui/QWidget>
#endif
#include <QLabel>
#include <QLineEdit>
#include <QComboBox>
#include <QTextEdit>
#include <QGridLayout>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPixmap>
class BaseInfo : public QWidget
{
Q_OBJECT
public:
explicit BaseInfo(QWidget *parent = nullptr);
signals:
public slots:
private:
//左側
QLabel *UserNameLabel; //用戶名
QLabel *NameLabel; //姓名
QLabel *SexLabel; //性別
QLabel *DepartmentLabel; //部門
QLabel *AgeLabel; //年齡
QLabel *OtherLabel; //備注
QLineEdit *UserNameLineEdit;
QLineEdit *NameLineEdit;
QComboBox *SexCombox;
QTextEdit *DepartmentTextEdit;
QLineEdit *AgeLineEdit;
QGridLayout *LeftLayout;
//右側
QLabel *HeadLabel; //右上角部分,頭像
QLabel *HeadIconLabel; //頭像圖標
QPushButton *UpdateHeadBtn; //更新按鈕
QHBoxLayout *TopRightLayout; //個人說明
QLabel *IntroductionLabel;
QTextEdit *IntroductionTextEdit;
QVBoxLayout *RightLayout;
};
#endif // BASEINFO_H
baseinfo.cpp
#include "baseinfo.h"
BaseInfo::BaseInfo(QWidget *parent) : QWidget(parent)
{
//*****左側*****
UserNameLabel = new QLabel(tr("用戶名:"));
UserNameLineEdit = new QLineEdit;
NameLabel = new QLabel(tr("姓名:"));
NameLineEdit = new QLineEdit;
SexLabel = new QLabel(tr("性別:"));
SexCombox = new QComboBox;
SexCombox->addItem(tr("男"));
SexCombox->addItem(tr("女"));
DepartmentLabel = new QLabel(tr("部門:"));
DepartmentTextEdit = new QTextEdit;
AgeLabel = new QLabel(tr("年齡:"));
AgeLineEdit = new QLineEdit;
OtherLabel = new QLabel(tr("備注:"));
OtherLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
//左側布局
LeftLayout = new QGridLayout();
LeftLayout->addWidget(UserNameLabel, 0, 0);
LeftLayout->addWidget(UserNameLineEdit, 0, 1);
LeftLayout->addWidget(NameLabel, 1, 0);
LeftLayout->addWidget(NameLineEdit, 1, 1);
LeftLayout->addWidget(SexLabel, 2, 0);
LeftLayout->addWidget(SexCombox, 2, 1);
LeftLayout->addWidget(DepartmentLabel, 3, 0);
LeftLayout->addWidget(DepartmentTextEdit, 3, 1);
LeftLayout->addWidget(AgeLabel, 4, 0);
LeftLayout->addWidget(AgeLineEdit, 4, 1);
LeftLayout->addWidget(OtherLabel, 5, 0, 1, 2);
LeftLayout->setColumnStretch(0, 1);
LeftLayout->setColumnStretch(1, 3);
//*****右側*****
//右上方
HeadLabel = new QLabel(tr("頭像:"));
HeadIconLabel = new QLabel;
QPixmap icon("123.png");
HeadIconLabel->setPixmap(icon);
HeadIconLabel->resize(20, 20);
UpdateHeadBtn = new QPushButton(tr("更新"));
//右上方布局
TopRightLayout = new QHBoxLayout;
TopRightLayout->setSpacing(20);
TopRightLayout->addWidget(HeadLabel);
TopRightLayout->addWidget(HeadIconLabel);
//右下方
IntroductionLabel = new QLabel(tr("個人說明:"));
IntroductionTextEdit = new QTextEdit;
//右下方布局
RightLayout = new QVBoxLayout();
RightLayout->setMargin(10);
RightLayout->addLayout(TopRightLayout);
RightLayout->addWidget(IntroductionLabel);
RightLayout->addWidget(IntroductionTextEdit);
//總布局
QGridLayout *mainLayout = new QGridLayout(this);
mainLayout->setMargin(15);
mainLayout->setSpacing(10);
mainLayout->addLayout(LeftLayout, 0, 0);
mainLayout->addLayout(RightLayout, 0, 1);
//mainLayout->setSizeConstraint(QLayout::SetFixedSize);
}
(2)Class Contact
contact.h
#ifndef CONTACT_H
#define CONTACT_H
#include <QtCore/qglobal.h>
#if QT_VERSION >= 0x050000
#include <QtWidgets/QWidget>
#else
#include <QtGui/QWidget>
#endif
#include <QLabel>
#include <QGridLayout>
#include <QLineEdit>
#include <QCheckBox>
class Contact : public QWidget
{
Q_OBJECT
public:
explicit Contact(QWidget *parent = nullptr);
signals:
public slots:
private:
QLabel *EmailLabel;
QLineEdit *EmailLineEdit;
QLabel *AddrLabel;
QLineEdit *AddrLineEdit;
QLabel *CodeLabel;
QLineEdit *CodeLineEdit;
QLabel *MoviTelLabel;
QLineEdit *MoviTelLineEdit;
QCheckBox *MoviTelCheckBox;
QLabel *ProTelLabel;
QLineEdit *ProTelLineEdit;
QGridLayout *mainLayout;
};
#endif // CONTACT_H
contact.cpp
#include "contact.h"
Contact::Contact(QWidget *parent) : QWidget(parent)
{
EmailLabel = new QLabel(tr("電子郵件:"));
EmailLineEdit = new QLineEdit;
AddrLabel = new QLabel(tr("聯系地址:"));
AddrLineEdit = new QLineEdit;
CodeLabel = new QLabel(tr("郵政編碼:"));
CodeLineEdit = new QLineEdit;
MoviTelLabel = new QLabel(tr("移動電話:"));
MoviTelLineEdit = new QLineEdit;
MoviTelCheckBox = new QCheckBox(tr("接收留言"));
ProTelLabel = new QLabel(tr("辦公電話:"));
ProTelLineEdit = new QLineEdit;
mainLayout = new QGridLayout(this);
mainLayout->setMargin(15);
mainLayout->setSpacing(10);
mainLayout->addWidget(EmailLabel, 0, 0);
mainLayout->addWidget(EmailLineEdit, 0, 1);
mainLayout->addWidget(AddrLabel, 1, 0);
mainLayout->addWidget(AddrLineEdit, 1, 1);
mainLayout->addWidget(CodeLabel, 2, 0);
mainLayout->addWidget(CodeLineEdit, 2, 1);
mainLayout->addWidget(MoviTelLabel, 3, 0);
mainLayout->addWidget(MoviTelLineEdit, 3, 1);
mainLayout->addWidget(MoviTelCheckBox, 3, 2);
mainLayout->addWidget(ProTelLabel, 4, 0);
mainLayout->addWidget(ProTelLineEdit, 4, 1);
mainLayout->setSizeConstraint(QLayout::SetFixedSize);
}
(3)Class Detail
detail.h
#ifndef DETAIL_H
#define DETAIL_H
#include <QtCore/qglobal.h>
#if QT_VERSION >= 0x050000
#include <QtWidgets/QWidget>
#else
#include <QtGui/QWidget>
#endif
#include <QLabel>
#include <QComboBox>
#include <QLineEdit>
#include <QTextEdit>
#include <QGridLayout>
class Detail : public QWidget
{
Q_OBJECT
public:
explicit Detail(QWidget *parent = nullptr);
signals:
public slots:
private:
QLabel *NationalLabel;
QComboBox *NationalComboBox;
QLabel *ProvinceLabel;
QComboBox *ProvinceComboBox;
QLabel *CityLabel;
QLineEdit *CityLineEdit;
QLabel *IntroductLabel;
QTextEdit *IntroductTextEdit;
QGridLayout *mainLayout;
};
#endif // DETAIL_H
detail.cpp
#include "detail.h"
Detail::Detail(QWidget *parent) : QWidget(parent)
{
NationalLabel = new QLabel(tr("國家/地址:"));
NationalComboBox = new QComboBox;
NationalComboBox->insertItem(0, tr("中國"));
NationalComboBox->insertItem(1, tr("美國"));
NationalComboBox->insertItem(2, tr("英國"));
ProvinceLabel = new QLabel(tr("省份:"));
ProvinceComboBox = new QComboBox;
ProvinceComboBox->insertItem(0, tr("江蘇省"));
ProvinceComboBox->insertItem(1, tr("山東省"));
ProvinceComboBox->insertItem(2, tr("浙江省"));
CityLabel = new QLabel(tr("城市:"));
CityLineEdit = new QLineEdit;
IntroductLabel = new QLabel(tr("個人說明:"));
IntroductTextEdit = new QTextEdit;
mainLayout = new QGridLayout(this);
mainLayout->setMargin(15);
mainLayout->setSpacing(10);
mainLayout->addWidget(NationalLabel, 0, 0);
mainLayout->addWidget(NationalComboBox, 0, 1);
mainLayout->addWidget(ProvinceLabel, 1, 0);
mainLayout->addWidget(ProvinceComboBox, 1, 1);
mainLayout->addWidget(CityLabel, 2, 0);
mainLayout->addWidget(CityLineEdit, 2, 1);
mainLayout->addWidget(IntroductLabel, 3, 0);
mainLayout->addWidget(IntroductTextEdit, 3, 1);
}
2、將底層頁面放在QStackWidget中
新建一個Content類,繼承自QFrame。在Content類中,創建一個QStackWidget對象,然后將上述三個頁面插入到此對象中。
content.h
#ifndef CONTENT_H
#define CONTENT_H
#include <QtCore/qglobal.h>
#if QT_VERSION >= 0x050000
#include <QtWidgets/QWidget>
#else
#include <QtGui/QWidget>
#endif
#include <QFrame>
#include <QStackedWidget>
#include <QGridLayout>
#include "baseinfo.h"
#include "contact.h"
#include "detail.h"
class Content : public QFrame
{
Q_OBJECT
public:
explicit Content(QWidget *parent = nullptr);
QStackedWidget *stack;
BaseInfo *baseInfo;
Contact *contact;
Detail *detail;
signals:
public slots:
private:
QGridLayout *mainLayout;
};
#endif // CONTENT_H
content.cpp
這里用了一個QGridLayou布局,布局中只有一個QStackWidget。如果去掉此布局,則在主界面中的Stack頁面無法隨主界面變化,只能保持同一個尺寸,所以這里有必要加一個布局。
#include "content.h"
Content::Content(QWidget *parent) : QFrame(parent)
{
stack = new QStackedWidget(this); //創建一個堆棧窗口對象
stack->setFrameStyle(QFrame::Panel | QFrame::Raised); //窗口的顯示風格
//插入頁面
baseInfo = new BaseInfo();
contact = new Contact();
detail = new Detail();
stack->addWidget(baseInfo);
stack->addWidget(contact);
stack->addWidget(detail);
mainLayout = new QGridLayout(this);
mainLayout->setMargin(2);
mainLayout->addWidget(stack, 0, 0);
}
3、主界面的實現
這里的主界面不是指main函數,而是指QMainWindow,主界面的類為MainStack繼承自QMainWindow。在主界面上主要實現的功能是狀態欄和Stack界面的顯示以及它們之間的連接。
mainstack.h
#ifndef MAINSTACK_H
#define MAINSTACK_H
#include <QMainWindow>
#include <QToolBar>
#include <QAction>
#include <QGridLayout>
#include "content.h"
class MainStack : public QMainWindow
{
Q_OBJECT
public:
MainStack(QWidget *parent = 0);
~MainStack();
Content *content;
QGridLayout *mainLayout;
void createAction(); //動作處理函數
void createToolBar(); //創建工具欄
private:
QToolBar *stackTool; //工具欄
QAction *openStack[3];
private slots:
void openBaseInfo(); //點擊狀態欄的槽函數
void openContact();
void openDtail();
};
#endif // MAINSTACK_H
mainstack.cpp
主界面的中心部件就一個,就不加布局了,所有的布局都加在上一步的QFrame中。
#include "mainstack.h"
MainStack::MainStack(QWidget *parent)
: QMainWindow(parent)
{
setWindowTitle(tr("主界面"));
setMinimumSize(800, 480);
createAction();
createToolBar();
content = new Content(this);
setCentralWidget(content); //將stack窗口設置為中心部件
//mainLayout = new QGridLayout(this);
//mainLayout->setMargin(15);
//mainLayout->setSpacing(10);
//mainLayout->addWidget(stackTool, 0, 0);
//mainLayout->addWidget(content, 1, 0);
}
MainStack::~MainStack()
{
}
//Action動作
void MainStack::createAction()
{
//轉到第一個界面
openStack[0] = new QAction(tr("基本信息"), this);
openStack[0]->setShortcut(tr("Ctrl+Q"));
openStack[0]->setStatusTip(tr("界面1"));
connect(openStack[0], SIGNAL(triggered(bool)), this, SLOT(openBaseInfo()));
//轉到第二個界面
openStack[1] = new QAction(tr("聯系方式"), this);
openStack[1]->setShortcut(tr("Ctrl+W"));
openStack[1]->setStatusTip(tr("界面2"));
connect(openStack[1], SIGNAL(triggered(bool)), this, SLOT(openContact()));
//轉到第三個界面
openStack[2] = new QAction(tr("詳細資料"), this);
openStack[2]->setShortcut(tr("Ctrl+E"));
openStack[2]->setStatusTip(tr("界面3"));
connect(openStack[2], SIGNAL(triggered(bool)), this, SLOT(openDtail()));
}
//創建工具欄
void MainStack::createToolBar()
{
stackTool = addToolBar("工具欄");
stackTool->addAction(openStack[0]);
stackTool->addAction(openStack[1]);
stackTool->addAction(openStack[2]);
}
//轉到界面1槽函數
void MainStack::openBaseInfo()
{
this->content->stack->setCurrentIndex(0);
}
//轉到界面2槽函數
void MainStack::openContact()
{
this->content->stack->setCurrentIndex(1);
}
//轉到界面3槽函數
void MainStack::openDtail()
{
this->content->stack->setCurrentIndex(2);
}
4、main函數
main函數就是顯示主界面。
#include "mainstack.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainStack w;
w.show();
return a.exec();
}
