信号和槽
1.信号和槽:
在生成一个按钮之后,如果没有后续的操作,那么这个按钮就像是摆设一样,而槽(后续的操作)没有信号的触发,也无法执行,因此需要一个函数将信号和槽进行连接:
//(信号的发送者,发送的信号,信号的接受者,信号的处理(槽));四个参数都是地址形式,其中参数2和参数4前边要加上“&”;
connect(mybtn,&QPushButton::cliicked,this,&QWidget::close);
信号和槽具有松散耦合的特点,也就是说信号和槽之间是相互独立的,需要连接才可以实现一种操作,而一个槽可以由不同的信号触发,比如说上述代码中点击按钮关闭窗口的操作,我可以通过这个按钮关闭,也可在别的地方通过点击别的按钮或者其他操作来关闭窗口。
2.自定义的信号和槽,以小明请小花吃饭为例,小花是信号的发出者,发出信号他饿了,小明是信号的接收者,请吃饭就是小明的对这个信号的处理,
新建一个项目,在项目中添加连个类,一个类级叫做teacher,一个类叫做student,两个类都不需要依附于对话框之类的,所以父类继承Qobject即可,由于老师是信号的发出者,所以在老师类的.h文件中的signals:下添加信好,void hungry();并且这个信号不需要实现,学生是信号的接受者,所以在学生类(qt5,4版本以后可以添加在public或者public sloits下边)的public:下添加槽函数void
treat();并且需要在.cpp文件实现。然后在主窗口类的私有成员中声明学生对st,和老师对象zt,在.cpp文件中对st,zt进行初始化:(分配内存空间)
zt=new Teacher(this);
st=new Student(this);
在主窗口函数中声明并实现一个函数叫做classIsOver();作用是用来触发老师饿了的函数,
void MainWindows::classIsOver()
{
qDebug()<<"老师请学生吃饭"<<endl;
}
然后将信号和槽进行连接
connect(zt,&Teacher::hungry,st,&Stundent::treat());
此时信号和槽已经连接,但是信号还没有被触发,再补上触发函数classIsOver();
classIsOver();
运行程序会看到在下边的Debug模块上显示 了“老师请学生吃饭”
3.自定义的信号和槽发生重载的解决
上图中的报错是因为在信号和槽进行连接时出现了重载的信号或槽。
比如说定义了两个槽函数
3.1
void treat()
{
qDebug<<"1111";
}
void treat(QString str)
{
qDebug<<"2222";
}
此时应该用函数指针来解决,定义一个函数的指针,让它指向其中一个函数的地址,在进行信号和槽的连接时,使用这个已经被定义好的函数指针所在地址,
//在声明成员函数的指针的时候,要将成员函数的作用域也加入进去,比如Teacher::*ip,
//后边跟随的括号中填写的是参数类型
void(Teacher::*ip1)(QString)=&Teacher::hungry;
void(Student::*ip2)(QString)=&Student::treat;
connect(zt,ip1,st,ip2);
classIsOver();
另外,connect会自动将信号函数的所有参数传递给槽函数。所以发送信号和槽函数都需要重载.
3.2信号和信号的连接
connect不仅可以实现信号和槽的连接,也可以实现信号和信号的连接,但需要注意的是,由于connect是将参数从前传递到后边,所以应该保证前后的信号发送和槽函数/信号发送2所具有的参数是一样的,因此,假如我想加入一个按钮实现点击这个按钮,老师就饿了,由于按钮点击按钮函数是不需要传递参数的,所以老师饿了的函数也应该用无参的
//定义函数指针
void(Student::*stuip1)()=&Student::treat;
void(Student::*stuip2)(QString)=&Student::treat;
void(Teacher::*ip1)()=&Teacher::hungry;
void(Teacher::*ip2)(QString)=&Teacher::hungry;
connect(zt,ip1,st,stuip1);
//connect(zt,ip2,st,stuip2);
//点击按钮触发下课
//connect(ui->pushButton,&QPushButton::clicked,this,&MainWindow::classIsOver);
//信号连接信号
connect(ui->pushButton,&QPushButton::clicked,zt,ip1);
//QPushButton *btn=new QPushButton("上课",this);
//connect(btn,&QPushButton::clicked,zt,ip1);
//信号连接信号
classIsOver();
同理也有disconnect()函数,用法和connect()函数一样,作用是断开信号连接。
Lambda表达式
形容}{}的就是lambda表达式,又叫做匿名函数,可以用于信号和槽的一些函数使得一些操作非常的方便。
- []标识符 匿名函数
1.1 []中添加“=”,值传递(推荐)
1.2 []中添加“&",引用传递(不推荐) - ()参数
- {}实现体
- mtable,写在()的后边,表示可以对传入进来的变量进行修改
- 样例1:
由于按钮点击信号后边对应的槽函数只能是无参的(因为按钮点击信号没有参数,所以传递过去的也没有参数),所以如果想通过点击按钮,同时槽函数使用带参的便可以使用匿名函数
QPushButton *btn2=new QPushButton(this);
btn2->move(100,100);
btn2->resize(100,100);
btn2->setText("吃饭");
connect(btn2,&QPushButton::clicked ,this,[=](){
//this->close();
emit st->treat("宫保鸡丁");
});
样例2:
//值传递
int t=1;
[=]()mutable {
t+=100;
qDebug()<<"匿名函数里边的"<<t;
}();//注意加上这个小括号就像函数一样。
qDebug()<<"匿名函数外边的"<<t;
qDebug()<<"\n";
//引用传递
int s=1;
[&s]()mutable {
s=s+100;
qDebug()<<"匿名函数里边的"<<s;
}();
qDebug()<<"匿名函数外边的"<<s;
}
值传递的结果是:101,1;
引用传递的结果是:101,101;
l
模态和非模态对话框的创建
在创建ui界面之后,想要通过点击菜单栏中的新建按钮弹出一个对话框
使用connect函数
//triggered是菜单栏,工具栏上按钮的触发函数,被定义在QAction类中
connect(ui->actionnew,&QAction::triggered,[=](){
//创建模态对话框
Dialog *dialog(this);//在栈区创建.调用完毕立即释放
dialog.resize(114,514);
dialog.exec();//创建模态对话框使用的函数,阻塞功能,窗口弹出后会停留在这,不会继续向下执行直到对话框关闭为止。
});
connect(ui->actionnew,&QAction::triggered,[=](){
//创建非模态对话框
Dialog *dialog2=new Diallog(this);
//将对象放在堆区使对象一直存活,防止窗口一闪而过。
dialog2->resize(200,100);
//显示对话框
dialog2->show();
//为了防止可能出现的内存泄露,设置dialog2的属性为WA_DeleteOnClose的含义是:每次只要关闭了对话框,
//就将对话框对象所分配的内存释放掉。(因为如果不这样做,当多次点击创建对话框对象并且没有关闭主窗口 时,创建对话宽对象所分配的内存一直不被释放,当这样的操作次数过多会造成内存泄露,因此设置只要关闭对话框,就将对话框对象所分配的内存释放掉)
dialog2->setAttribute(Qt::WA_DeleteOnClose);
});
消息对话框
消息对话框QMessageBox 类提供一个模态的对话框来通知一些信息,或者向用户提出一个问题并且获取答案等。比如,点击按钮弹出一个对话框,对话框分四种(错误(critical),信息(information),提问(information),警告(waring))。
在connect中通过匿名函数实现:
比如QMessageBox::question(this,“question”,“问题”,QMessageBox::Save | QMessageBox::Cancel,QMessageBox::Cancel);
参数1:父亲
参数2:标题栏内容
参数3:描述
参数4:按键类型
参数5:默认关联回车的按键
参数5通常在question中才有意义,因为有两个按键,而其他的对话框只有一个按键,默认关联回车的只能是那一个键,所以参数5通常省略。
connect(btn3,&QPushButton::clicked,this,[=](){
//QMessageBox::critical(this,"crticial","错误");
//QMessageBox::information(this,"information","信息");
//对话框返回的是一个int值,可以用一个int变量来接收。
int ret=QMessageBox::question(this,"question","问题",QMessageBox::Save | QMessageBox::Cancel,QMessageBox::Cancel);
switch(ret)
{
case QMessageBox::Save:
qDebug()<<"点击了保存按钮";
break;
case QMessageBox::Cancel:
qDebug()<<"点击了取消按钮";
break;
}
/*if(QMessageBox::Save==QMessageBox::question(this,"question","问题",QMessageBox::Save | QMessageBox::Cancel,QMessageBox::Cancel)){
qDebug()<<"点击了保存按钮";
}
else
qDebug()<<"点击了取消按钮";
*/
//QMessageBox::warning(this,"warning","警告");
});