Qt学习记录-信号和槽机制

当某个时间发生后,比如某个按钮被点击了一下,它就会广播一个信号(signal),如果某个对象对这个信号感兴趣,那么可以使用链接函数(connect)订阅这个信号,当收到信号时,被链接的槽函数(slot)会自动被回调,这就是信号和槽机制。

图示:

语法:

  • connect(信号发出者(对象),&信号(本质是一个函数,地址传递),信号接收者,槽函数(是一个函数,地址传递))

示例:系统自带的信号与槽:

  • 创建一个按钮,令其被点击时关闭窗口
1
2
3
4
myButton=new QPushButton("关闭窗口",this);//在堆区创建一个按钮,令其父对象为此窗口

connect(myButton,&QPushButton::clicked,this,&QWidget::close);
//创建一个connect,注意函数要地址传递

链接的断开

disconnect,用法与connect相同

1
disconnect(myButton,&QPushButton::clicked,t,teacherSignal);

自定义信号和槽中信号的激活

可以用emit运算符来激活信号

1
emit 对象指针->函数;//激活对应函数

槽发生重载的解决

有时候,当槽函数发生重载时,传统的connect写法Qt不知道该调用哪一个,这个时候要用到函数指针来解决问题。

示例:

有两个类,teacher类和student类。当teacher类调用其hungry()函数(signal)时,student类响应,调用eat()函数(slot)

teacher类:

1
2
3
4
5
signals:
//自定义的信号写到signals下,只需要声明
void Hungry();
void Hungry(QString foodname);
//这里的hungry发生了重载,我们希望调用Hungry的带QString参数的那一个

student类:

1
2
3
4
5
6
7
8
9
10
void Student::Eat()
{
qDebug()<<"吃东西";
}

void Student::Eat(QString food)
{
qDebug()<<"吃东西"<<food.toUtf8().data();
}
//这里student类的eat函数也发生了重载,我们希望其调用带QString参数的那一个

widget部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//创建一个老师的对象
this->t=new Teacher(this);

//创建一个学生的对象
this->s=new Student(this);

//重载情况下的链接
void(Teacher::*teacherSignal)(QString)=&Teacher::Hungry;
void(Student::*studentSignal)(QString)=&Student::Eat;
connect(t,teacherSignal,s,studentSignal);

this->myButton=new QPushButton("下课",this);
myButton->resize(100,100);

emit t->Hungry("大嘴吧子");//也可以利用emit调用

可以看到,这里利用了函数指针来设置connect,使其明确的指向带参数的函数

1
2
void(Teacher::*teacherSignal)(QString)=&Teacher::Hungry;
void(Student::*studentSignal)(QString)=&Student::Eat;

void(类作用域下的一个指针)(明确参数)= 对应类作用域下的函数地址

带参数的信号和槽中参数的转递问题

信号函数在广播信号时,会连带其参数列表(类型,顺序)一起发出,让槽函数接收到。由此,信号函数的参数和槽函数的参数顺序,类型要对应,且信号函数的参数个数不能少于槽函数的参数个数

lambda表达式解决函数调用问题

lambda表达式相当于一个匿名函数

格式:

[ 模式 ] {参数} ->返回值类型 { 函数主体 }

其中模式填 = 表示值传递,& 表示引用传递,这里饥馑是为了让lambda表达式能识别函数体内的变量,一般采用 =

示例:用lambda解决信号和槽的带参函数的问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//创建一个老师的对象
this->t=new Teacher(this);
//创建一个学生的对象
this->s=new Student(this);

void(Teacher::*th)(QString) = &Teacher::Hungry;
connect(t,th,this,[=](QString food){
s->Eat(food);
});
//lambda表达式

this->myButton=new QPushButton("下课",this);
myButton->resize(100,100);
myButton->move(150,250);

connect(myButton,&QPushButton::clicked,this,[=](){
emit t->Hungry("大嘴巴子");
});
//lambda表达式