1.重载自定义信号与槽:
定义天黑类:里面有一个有参数的信号和没有参数的信号
tianhei.h
#ifndef TIANHEI_H
#define TIANHEI_H
#include
class Tianhei : public QObject
{
Q_OBJECT
public:
Tianhei(); //构造函数声明
signals:
void tianhei();
void tianhei(QString name); //信号只需声明
public slots:
};
#endif // TIANHEI_H
定义想你类:同样一个有参数一个没有参数
xingni.h
#ifndef XINGNI_H
#define XINGNI_H
#include
class Xingni : public QObject
{
Q_OBJECT
public:
explicit Xingni(QObject *parent = nullptr);
signals:
public slots:
void xiangni();
void xiangni(QString name); //槽函数
};
#endif // XINGNI_H
xingni.c
#include "xingni.h"
#include
Xingni::Xingni(QObject *parent) : QObject(parent)
{
}
void Xingni::xiangni(){
qDebug()<<"想你了";
}
void Xingni::xiangni(QString name){
qDebug()<<"想你了"<
我们选择第一种按键绑定方式,即用中转函数,
点击按钮,按钮发送点击信号,MainWindow接收信号,执行heilai()函数;
heilai()函数会让hei发送tianhei信号,xing接收信号执行xingni槽函数;
但是我们发现,由于信号函数和槽函数存在两个重名的函数,一个有参数,一个没有参数,程序存在歧义,不知道执行哪一个,这时候就是指针大显身手的时候了。我们定义一个函数体指针分别接收有参数的信号函数和槽函数,把两个指针传到connect中去就好了;
mainwindow.c
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("love");
//设置固定大小,设置完成不可拉伸
this->setFixedSize(400,300);
QPushButton *butten=new QPushButton("点我天黑",this);
butten->move(150,100);
//定义一个按钮实例子
this->hei =new Tianhei(); //实例化对象,注意后面括号
this->xing =new Xingni();
void (Xingni::*XINGNI)(QString)=&Xingni::xiangni;
void (Tianhei::*TIANHEI)(QString)=&Tianhei::tianhei;
// connect(butten,&QPushButton::clicked,hei,XINGNI);
connect(butten,&QPushButton::clicked,this,&MainWindow::heilai);
connect(hei,TIANHEI,xing,XINGNI);
//天黑发出天黑信号,xing接收,调用槽函数;
}
void MainWindow::heilai(){
qDebug()<<"天要黑了!";
emit hei->tianhei("刘亦菲"); //定义的有参数所以要传参
}
MainWindow::~MainWindow()
{
delete ui;
}
void (Xingni::*XINGNI)(QString)=&Xingni::xiangni;
void (Tianhei::*TIANHEI)(QString)=&Tianhei::tianhei;
void是函数返回值,(Xingni::*XINGNI)(QString)=&Xingni::xiangni;XINGNI中是Xingni::xiangni的地址,由于前边有参数,因此会自动传有参数的函数地址。
QString----->QByteArray-------->char * 去引号
qDebug()<<"想你了"<
2.信号与槽总结
(1)发送者与接收者是需要是QObjec的子类(槽函数是全局,lambda除外)
(2)信号与槽返回值都是void类型。
(3)信号只需要声明不需要定义实现,槽函数需要声明也需要实现(注意继承方式,public,private,protected)。
(4)槽函数是普通函数,会受到public,private,protected影响。
(5)使用emit在恰当的位置发送信号
(6)任何成员函数,static函数,全局函数和Lambda表达式都可以作为槽函数
(7)使用connect()函数连接信号与槽
(8)信号与槽的参数要一致,参数类型一致,槽函数参数可以比信号少,但是顺序要一直。
举例:
signal(Qstring)和slot(Qstring)
signal(Qstring,Qstring)和slot(Qstring)
signal(Qstring,Qstring)和slot(Qstring,int)错误
signal(Qstring,Qstring,int)和slot(Qstring,Qstring)
signal(Qstring,Qstring,int)和slot(Qstring,int) 错误
(9)信号与槽可以一对一,一对多(发出信号,槽函数一个一个执行,顺序不确定)多对一(发出任意一个信号,槽函数都执行)
(10)信号可以连接信号
(11)槽可以断开连接(disconnect),槽可以被取消连接(当一个对象delete了,取消这个连接)
(12)可以使用C++11中的lambda
3.Lambda表达式
格式:[capture] (parameters) mutable -> return-type {statement}
(1)[ ]标识一个Lambda的开始,这部分必须存在,不能省略
(2)()参数列表,如果不需要传递参数的话,()可以一同省略
(3)如果使用mutable,参数列表()不能省略,即使参数为空。如果使用mutable修改拷贝,值本身不变。
(4) -> return-type返回值类型,如果不需要可以省略;
(5){statement}函数体,可以使用参数列表,也可以使用捕获列表;
1)传参Lambda
#include
using namespace std;
int main() {
int a = 1, b = 2;
auto A1 = [](int x, int y)->int {return x + y; };
cout << A1(a, b);
return 0;
}
2)捕获列表(只读)
利用捕获列表传参
#include
using namespace std;
int main() {
int a = 1, b = 2;
auto A1 = [a,b]()->int {return a + b; };
cout << A1();
return 0;
}
此时不能修改a和b的值,因为默认传参方式是“=”,只有读权限,没有修改权限
#include
using namespace std;
int main() {
int a = 1, b = 2,c=3;
auto A1 = [=]()->int {return a + b+c; };
cout << A1();
return 0;
}
[=]将匿名函数范围内的所有局部变量捕获
2)捕获列表(修改)
#include
using namespace std;
int main() {
int a = 1, b = 2, c = 3;
auto A1 = [&]()->int { a = 3, b = 3; return a + b + c; };
cout << "a=" << a << endl << "b=" << b << endl << "c=" << c << endl;
cout << A1();
return 0;
}
[&] 引用传值,因此可以改变值,但是改变的值是copy的值,函数外的值不改变。
#include
using namespace std;
int main() {
int a = 1, b = 2, c = 3;
auto A1 = [=]()mutable->int { a = 3, b = 3; return a + b + c; };
cout << "a=" << a << endl << "b=" << b << endl << "c=" << c << endl;
cout << A1();
return 0;
}
4.MainWindow:提供对话框
一个菜单栏(menu bar),多个工具栏(tool bar),多个铆接部件(dock widgets)(浮动窗口),一个状态栏(status bar),一个中心部件(central widget)
1)菜单栏:
(1)菜单栏类QMenuBar:创建菜单栏
(2)菜单类QMenu:创建菜单
(3)QAction:充当子菜单
QMenuBar *menubar=new QMenuBar(this); //创建菜单栏两种方法
QMenuBar *menubar=menuBar();
this->setMenuBar(menubar); //添加到该页面中
QMenu *menu1=new QMenu("文件"); //创建菜单
menubar->addMenu(menu1) //将menu添加到menubar菜单栏中
QAction *act1=new QAction("打开文件"); //创建子菜单
menu1->addAction(act1); //将act1添加menu1子菜单中
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
#include
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
resize(800,600);
ui->setupUi(this);
// QMenuBar *menubar=new QMenuBar(this);
QMenuBar *menubar=menuBar();
//创建菜单栏
this->setMenuBar(menubar);
//创建菜单
QMenu *menu1=new QMenu("文件");
QMenu *menu2=new QMenu("编辑");
QMenu *menu3=new QMenu("构建");
QMenu *menu4=new QMenu("调试");
QMenu *menu5=new QMenu("Analyze");
QMenu *menu6=new QMenu("工具");
QMenu *menu7=new QMenu("控件");
QMenu *menu8=new QMenu("帮助");
menubar->addMenu(menu1);
menubar->addMenu(menu2);
menubar->addMenu(menu3);
menubar->addMenu(menu4);
menubar->addMenu(menu5);
menubar->addMenu(menu6);
menubar->addMenu(menu7);
menubar->addMenu(menu8);
QAction *act1=new QAction("新建文件");
QAction *act2=new QAction("打开文件");
QAction *act3=new QAction("另存为");
QAction *act4=new QAction("关闭");
QAction *act5=new QAction("最近访问文件");
QAction *act6=new QAction("保存文件");
QAction *act7=new QAction("打印");
QAction *act8=new QAction("退出");
menu1->addAction(act1);
menu1->addAction(act2);
menu1->addAction(act3);
menu1->addAction(act4);
menu1->addAction(act5);
menu1->addAction(act6);
menu1->addAction(act7);
menu1->addAction(act8);
connect(act1,&QAction::triggered,[=](){qDebug()<<"已新建文件";});
connect(act2,&QAction::triggered,[=](){qDebug()<<"已打开文件";});
connect(act3,&QAction::triggered,[=](){qDebug()<<"已另存为文件";});
connect(act4,&QAction::triggered,this,&MainWindow::close);
connect(act5,&QAction::triggered,[=](){qDebug()<<"最近访问文件";});
connect(act6,&QAction::triggered,[=](){qDebug()<<"已保存文件";});
connect(act7,&QAction::triggered,[=](){qDebug()<<"打印文件";});
connect(act8,&QAction::triggered,[=](){qDebug()<<"退出";});
}
MainWindow::~MainWindow()
{
delete ui;
}
这样一个简易的菜单栏就写完了
点击就会执行自己定义的函数,接下来只需要真正保存,新建文件等函数就可以了,我只写了关闭,别的用Lambda代替,实测是可以的。