1.相关概念:
[1].信号(Signal)就是在特定情况下被发射的事件
[2].槽(Slot)就是对信号响应的函数。槽就是一个函数
[3].信号与槽之间的关联:是用 QObject::connect() 函数实现的,其基本格式是:
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
//信号发出者,处理的信号, 信号接收者,处理动作方法(槽函数)。
注解:
[1].sender 是发射信号的对象的名称,
[2].signal() 是信号名称。信号可以看做是特殊的函数,需要带括号,有参数时还需要指明参数。
[3].receiver 是接收信号的对象名称,slot() 是槽函数的名称,需要带括号,有参数时还需要指明参数。
[4].SIGNAL 和 SLOT 是 Qt 的宏,用于指明信号和槽,并将它们的参数转换为相应的字符串。
使用时需注意:
[1].一个信号可以连接多个槽, 当一个信号与多个槽函数关联时,槽函数按照建立连接时的顺序依次执行,例如:
connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(addFun(int));
connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(updateStatus(int));
[2]. 多个信号可以连接同一个槽,
connect(ui->rBtnBlue,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnRed,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnBlack,SIGNAL(clicked()),this,SLOT(setTextFontColor()))
[3]. 一个信号可以连接另外一个信号
[4]. 严格的情况下,信号与槽的参数个数和类型需要一致,至少信号的参数不能少于槽的参数。如果不匹配,会出现编译错误或运行错误。
[5]. 在使用信号与槽的类中,必须在类的定义中加入宏 Q_OBJECT
[6]. 当一个信号被发射时,与其关联的槽函数通常被立即执行,就像正常调用一个函数一样。只有当信号关联的所有槽函数执行完毕后,才会执行发射信号处后面的代码。
2.自定义槽
可当作槽函数的:任意的成员函数,普通全局函数,静态函数。
槽函数需要和信号一致(参数列表,返回值)如果信号没有返回值,槽函数一定没有返回值。
【举例】:让按钮2点击一下,就能改变按钮上的文本。
[1].首先,在.h文件中声明:
[2]在.cpp文件对该函数进行定义:
[3]给按钮联结自定义的槽函数 mySlot:
connect(b2, &QPushButton::released, this, &MainWidget::mySlot);
[4].运行
3.自定义信号
1.信号必须有signals关键字来声明
2.信号没有返回值,但可以有参数。
3.信号就是函数的声明,只需声明,无需定义。
4.emit发射信号
emit是Qt关键字,像其他关Qt扩展一样,它也会被C++预处理器转换成标准的C++代码。
使用:在A中对B使用信号
主要步骤:信号的创建,槽函数的创建,A类信号和B类槽函数的联接和使用
***A类的cpp***
void A::Dome()
{
B = new B;
******//在这里要先将B类实例化***
***//信号与槽需要实例化对象******
connect(this, SIGNAL(mySignal()), B, SLOT( BmySlot1()));
***//将A类的信号和B类的槽函数链接起来***
emit void AmySignal();
***//发出信号***
}
***B类的cpp***
void B::BmySlot1()
{
printf("hello world\n");
***//实现***
}
【举例】
需求:有两个窗口:主窗口和子窗口,让主窗口的按钮能跳转到子窗口,子窗口的按钮能跳转到主窗口。
疑问点:从主窗口跳转到子窗口,因为主窗口中有子窗口对象。但是要在子窗口中显示主窗口,由于子窗口中没有主窗口的对象。也不能有,否则进入死循环,逻辑错误。
[1].在main函数中把主窗口MainWidget加入进程
int main(int argc, char *argv[])
{
QApplication a(argc, argv); //创建一个QApplication类对象,有且只有一个应用程序对象!
MainWidget w1;
w1.show();
return a.exec();
}
[2].创建主窗口,在主窗口中创建一个按钮,并connect到槽函数
setWindowTitle("老大"); //给窗口命名。
but3.setParent(this);
but3.setText("切换到子窗口");
but3.move(50,50);
connect(&but3, &QPushButton::released,this,&MainWidget::changeWin);
//在主窗口类中定义和声明槽函数MainWidget::changeWin
public: void changeWin();
void MainWidget::changeWin(){
//子窗口显示
w.show();
//本窗口隐藏
this->hide();
}
[3].创建子窗口,并让子窗口加入到主窗口。
创建子窗口文件widget.h/widget.cpp
在主窗口文件中声明子窗口
private: Widget w;
[4]在主窗口中处理子窗口信号
// 先给子窗口添加自定义信号:mySignal,并connect到主窗口的dealSub槽函数
connect(&w, &Widget::mySignal,this,&MainWidget::dealSub);
// mySignal():在子窗口中有申明信号函数:但是没有定义
signals:void mySignal(); //在子窗口中申明信号函数
// dealSub():在主窗口中申明和定义槽函数
public :void dealSub();//申明:
//在相关.cpp文件中定义
void MainWidget::dealSub(){
w.hide();//子窗口隐藏
show(); //本窗口显示
}
[5].在子窗口中添加按钮,并让其实现跳转到主窗口
1).在子窗口文件中添加按钮
b3.setParent(this); //通过setParent指定父级
b3.setText("返回上一级窗口");
b3.resize(200, 40);//设置按钮的大小
b3.move(200, 200);//以Qwidget左上角为(0, 0),移动按钮
2).给按钮信号connect子窗口的sendSlot槽函数。
connect(&b3, &QPushButton::clicked,this,&Widget::sendSlot);
3).在子窗口类中声明和定义槽函数
public:void sendSlot();
4).定义槽函数:
void Widget::sendSlot(){
emit mySignal(); //触发子窗口的mySignal()信号。
}
mySinal()函数子窗口中有申明,但没有一个具体实现,这是为何?
答案请看《自定义信号的定义规则第3条》