学习笔记第二篇,利用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();
}