在上一章节中,我们已经搭建了一个很简陋的框架,这一章节我们继续细化,重点是通过信号与槽函数实现一些动态效果。
因为咱们这个软件有登录和注册的功能。所以得单独建一个登录窗口,用户在主窗口点击登录按钮,就会弹出这个子窗口,供用户输入账号密码进行登录。
这里我们可以用一个QDialog类型的控件来创建登录窗口,原型设计如下:
QDidalog是一个对话框控件,我们通过继承这个类,来实现这个登录窗口。
点击Qt Creator的文件->新建文件或项目->文件和类->C++ Class,类命名为loginDialog,基本类选择
新建完成后,点击logindialog.h头文件,编辑如下内容:
#ifndef LOGINDIALOG_H
#define LOGINDIALOG_H
#include
class loginDialog : public QDialog
{
Q_OBJECT
public:
loginDialog(QWidget *parent = nullptr);
~loginDialog();
};
#endif // LOGINDIALOG_H
我们在这里新建了一个继承自QDialog的自定义类,类里面暂时还没添加什么东西;
在logindialog.cpp源文件里面编辑好构造函数和析构函数;
#include "logindialog.h"
loginDialog::loginDialog(QWidget *parent)
: QDialog(parent)
{
}
loginDialog::~loginDialog()
{
}
接下来,我们点开mainwindow的头文件,在MainWindow中添加一个loginDialog的成员,当然,这之前加上这个logindialog.h的头文件。
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include "logindialog.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
void creatMenu();
void creatTool();
void creatNaviBar();
void creatStackWidget();
QStackedWidget *stackWidget;
loginDialog *myLoginDialog;
private slots:
};
#endif // MAINWINDOW_H
接着我们在mainwindow.cpp的creatTool()添加如下内容:
myLoginDialog = new loginDialog(this);
connect(loginAct,&QAction::triggered,myLoginDialog,&QDialog::show);
这里新建了登录窗口示例,并通过connect函数将loginAct动作按钮的触发信号和登录窗口的显示槽函数连接在一起,就是说只要登录按钮被点击,登录窗口就会显示。
再次运行,发现点击登录,会弹出一个空白的对话框窗口。
接下来我们将登录对话框补充完整,按照原型设计,这个对话框包含两个标签,两个文本输入框,两个按钮,整体布局也很规整,但最后一行的列宽和前两行的列宽不一致,所以不能简单的通过表格布局来完成,我们可以通过QGridLayout,QHboxLayout,QVboxLayout综合使用进行布局。
整个页面可以切分成2*4的一个表格,如下所示:
在logindialog.h中声明所有的子控件,包括两个标签,两个文本框,两个按钮,代码如下:
#ifndef LOGINDIALOG_H
#define LOGINDIALOG_H
#include
#include
#include
#include
class loginDialog : public QDialog
{
Q_OBJECT
public:
loginDialog(QWidget *parent = nullptr);
~loginDialog();
QLabel *nameLabel;
QLabel *passwordLabel;
QLineEdit *nameEdit;
QLineEdit *passwordEdit;
QPushButton *loginButton;
QPushButton *registButton;
};
#endif // LOGINDIALOG_H
在logindialog.cpp中的构造函数中,补充如下内容:
loginDialog::loginDialog(QWidget *parent)
: QDialog(parent)
{
nameLabel = new QLabel("用户名");
passwordLabel = new QLabel("密码");
nameEdit = new QLineEdit;
passwordEdit = new QLineEdit;
loginButton = new QPushButton("登录");
registButton = new QPushButton("注册");
QGridLayout *gridLayout = new QGridLayout;
gridLayout->addWidget(nameLabel,0,0);
gridLayout->addWidget(nameEdit,0,1);
gridLayout->addWidget(passwordLabel,1,0);
gridLayout->addWidget(passwordEdit,1,1);
QHBoxLayout *hLayout = new QHBoxLayout;
hLayout->addWidget(loginButton);
hLayout->addWidget(registButton);
QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->addLayout(gridLayout);
vLayout->addLayout(hLayout);
setLayout(vLayout);
}
运行一下,点击登录按钮,可以发现,现在这个登录界面已经基本成型了。
上一个章节中,我们已经通过QStackedWidget添加了6个页面,下面我们将左侧的导航条的6个动作按钮和这6个页面关联在一起,点击不同的按钮,显示不同的页面。
我们把creatNaviBar()函数中那6个临时的动作按钮变成mainwindow的全局变量,在头文件中将它们声明好。
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
void creatMenu();
void creatTool();
void creatNaviBar();
void creatStackWidget();
QStackedWidget *stackWidget;
loginDialog *myLoginDialog;
QAction *homeAction;
QAction *supplierAction;
QAction *goodsAction;
QAction *stockAction;
QAction *infoAction;
QAction *userAction;
};
把creatNaviBar()修改为:
void MainWindow::creatNaviBar()
{
QToolBar *naviBar = new QToolBar("导航",this);
addToolBar(Qt::LeftToolBarArea,naviBar);
homeAction = new QAction("主页",this);
naviBar->addAction(homeAction);
supplierAction = new QAction("供应商管理",this);
naviBar->addAction(supplierAction);
goodsAction = new QAction("商品管理",this);
naviBar->addAction(goodsAction);
stockAction = new QAction("库存管理",this);
naviBar->addAction(stockAction);
infoAction = new QAction("信息管理",this);
naviBar->addAction(infoAction);
userAction = new QAction("用户管理",this);
naviBar->addAction(userAction);
naviBar->setMovable(false);
}
接下来,我们在其他地方也可以调用这些动作按钮啦。
我们在mainwindow中添加一个槽函数void switchPages(),在函数体中编辑如下内容:
void MainWindow::switchPages()
{
QAction *action = qobject_cast(sender());
if(action->text() == "主页")
stackWidget->setCurrentIndex(0);
if(action->text() == "供应商管理")
stackWidget->setCurrentIndex(1);
if(action->text() == "商品管理")
stackWidget->setCurrentIndex(2);
if(action->text() == "库存管理")
stackWidget->setCurrentIndex(3);
if(action->text() == "信息管理")
stackWidget->setCurrentIndex(4);
if(action->text() == "用户管理")
stackWidget->setCurrentIndex(5);
}
这个函数的意思是,我先看下触发这个槽函数的信号发射者是谁,我把发射者转换为动作按钮,如果这个按钮名字和导航栏按钮的文字相符和,那么,堆栈容器就显示相应按钮对应的页面,注意,堆栈容器的索引是从0开始的。
我们在mainwindow的构造函数中将导航栏的6个按钮和这个槽函数连接在一起:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
creatMenu();
creatTool();
creatNaviBar();
creatStackWidget();
connect(homeAction,&QAction::triggered,this,&MainWindow::switchPages);
connect(supplierAction,&QAction::triggered,this,&MainWindow::switchPages);
connect(goodsAction,&QAction::triggered,this,&MainWindow::switchPages);
connect(stockAction,&QAction::triggered,this,&MainWindow::switchPages);
connect(infoAction,&QAction::triggered,this,&MainWindow::switchPages);
connect(userAction,&QAction::triggered,this,&MainWindow::switchPages);
}
运行一下,可以发现,点击不同的按钮,可以显示不同的页面。
导航栏现在还比较朴素,为了美观,我们为导航栏的每个按钮添加icon。
首先,我们用Photoshop或者sketch等绘图软件切出icon的png格式的文件,因为png可以支持透明背景。切好后的图标用图标代表的内容命名,比如主页按钮的图标,我命名为home.png,尽量命名规范一些,后续在代码中调用会方便一些。
我们把切好的图标放到项目文件目录中的一个文件夹中,文件夹命名为images,切图文件就准备好了。
然后,需要我们先为工程添加资源文件,点击文件->新建文件或项目->文件和类->Qt->Qt Resource File
名字我这里命名为resource。新建成功后,在项目文件窗口能看到项目中增加了一个resource.qrc文件。
我们点击添加->添加前缀,把前缀的输入框编辑为“/”
然后在项目窗口中选择resource.qrc,右键选择添加现有目录,在弹出的窗口中,勾选好刚才咱们准好的images目录,其他的项目文件不要勾。
然后,可以看到项目窗口中的qrc文件可以展开,包含了咱们刚才准备好的图标文件了,接下来我们就可以在项目中直接使用这些图标了。
在creatNaviBar()中,将代码修改如下:
void MainWindow::creatNaviBar()
{
QToolBar *naviBar = new QToolBar("导航",this);
naviBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
addToolBar(Qt::LeftToolBarArea,naviBar);
const QIcon homeIcon = QIcon::fromTheme("home", QIcon(":/images/home.png"));
homeAction = new QAction(homeIcon,"主页",this);
naviBar->addAction(homeAction);
const QIcon supplierIcon = QIcon::fromTheme("supplier", QIcon(":/images/supplier.png"));
supplierAction = new QAction(supplierIcon,"供应商管理",this);
naviBar->addAction(supplierAction);
const QIcon goodsIcon = QIcon::fromTheme("goods", QIcon(":/images/goods.png"));
goodsAction = new QAction(goodsIcon,"商品管理",this);
naviBar->addAction(goodsAction);
const QIcon stockIcon = QIcon::fromTheme("stock", QIcon(":/images/stock.png"));
stockAction = new QAction(stockIcon,"库存管理",this);
naviBar->addAction(stockAction);
const QIcon infoIcon = QIcon::fromTheme("info", QIcon(":/images/info.png"));
infoAction = new QAction(infoIcon,"信息管理",this);
naviBar->addAction(infoAction);
const QIcon userIcon = QIcon::fromTheme("user", QIcon(":/images/user.png"));
userAction = new QAction(userIcon,"用户管理",this);
naviBar->addAction(userAction);
naviBar->setMovable(false);
}
我们用QIcon这个控件将图标文件置入,然后在每个动作按钮中加入QIcon。记得最开始要把QToolBar的按钮风格设置为文字在图标下面。
运行一下,就可以看到导航栏的按钮已经加上图标啦。
好了,到这里,我们基本上把这个软件比较粗糙的UI大框架已经搭完了,虽然还是挺丑的,后续我们会单开一个章节把页面美化一下,现阶段先以实现功能为主。