目录
前言
在Qt
中理解信号与槽机制非常重要,在Qt
中进行了一段时间的开发之后,虽然也能够简单的使用信号与槽完成任务,但是却无法把程序写好。所以,加深对信号与槽的认知非常有必要。
学习!分享!感谢!
信号与槽简单使用
自定义信号与槽注意:
1、类的声明和实现分别放在.h
和.cpp
文件中(在头文件中用signals
声明一个信号,public slots
声明一个槽函数)
2、类声明中包含Q_OBJECT
宏
3、信号只要声明不需要设计其函数实现
4、发射信号用emit
关键字
5、自定义槽的实现和普通成员函数实现一样
补充:自定义信号与槽的参数列表应该相同,或者信号的参数多于槽的参数,但是注意槽的参数应该和信号的参数一一对应。
如果不对应会出现类似如下错误:
QObject::connect: Incompatible sender/receiver arguments
Widget::sigTest(QPoint&) --> Widget::slotTest3(QRect&)
这里我定义的sigTest(QPoint&)
是自定义信号,slotTest3(QRect&)
是自定义槽,因为参数不匹配,所以执行的时候对应的槽函数不会执行。
- Qt4中信号与槽的使用方法
参考Qt之信号与槽
connect(sender, SIGNAL(signal), receiver, SLOT(slot));
sender
和receiver
是指向QObject
的指针,signal
是信号,slot
是槽函数。
- Qt5中信号与槽的使用方法
connect(sender, &Sender::signal, receiver, &Receiver::slot);
- 编译器检查信号与槽是否存在,参数类型检查,
Q_OBJECT
宏是否存在。- 信号可以和槽函数、类的普通成员函数、
lambda
函数连接(不在局限于信号和槽函数)- 参数可以是
typedef
或者使用不同的namespace specifier
[不懂诶]- 可以允许一些自动类型转换(即信号与槽函数类型不必完全匹配)
- 参考代码
/* main.cpp
***********/
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
/* widget.h
***********/
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
#include <QDebug>
class Widget : public QWidget
{
Q_OBJECT // all the signals and slots have to include this
public:
Widget(QWidget *parent = 0);
~Widget();
signals:
void sigTest(QPoint &Qp); // signal implementation does not require a function prototype
void sigTest_qt5(QPoint &Qp);
private slots:
void slotTest1();
void slotTest2(QPoint& Qp);
// void slotTest3(QRect& rect);
void slotTest3();
void slotTest4(QPoint& Qp);
private:
QPushButton* pb;
QLineEdit* lEdit;
QLabel* label;
QPoint Qp;
};
#endif // WIDGET_H
#include "widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
// set widget position
setGeometry(90, 90, 300, 200);
// set pushButton position
pb = new QPushButton("Modify", this);
pb->setGeometry(10, 10, 100, 20); // x, y, w, h
// set lineEdit text and position
lEdit = new QLineEdit("what's your name", this);
lEdit->setGeometry(10, 30, 200, 150);
// set label position
label = new QLabel("My Label", this);
label->setGeometry(115, 10, 100, 20);
// clicked() is Qt's signal
// slotTest1 do not have parameter
connect(pb, SIGNAL(clicked()), this, SLOT(slotTest1()));
// sigTest's param is same to slotTest's param
connect(this, SIGNAL(sigTest(QPoint&)), this, SLOT(slotTest2(QPoint&)));
// connect(this, SIGNAL(sigTest(QPoint&)), this, SLOT(slotTest3(QRect&)));
// sigTest's have param, but slotTest3 don't have param
connect(this, SIGNAL(sigTest(QPoint&)), this, SLOT(slotTest3()));
// qt5 signals and slots
connect(this, &Widget::sigTest_qt5, this, &Widget::slotTest4);
}
Widget::~Widget()
{
}
void Widget::slotTest1()
{
lEdit->setText("SIMON");
label->setText("TTT"); // set label text
Qp.setX(10);
Qp.setY(10);
if(label->text() != "My Label")
{
emit sigTest(Qp);
emit sigTest_qt5(Qp);
}
}
void Widget::slotTest2(QPoint& Qp)
{
lEdit->setText("signal"); // if sigTest() is activate, lineEdit text will be changed
qDebug() << "Qp.x()=" << Qp.x() << " Qp.y()=" << Qp.y();
}
//void Widget::slotTest3(QRect& rect)
void Widget::slotTest3()
{
qDebug() << "slotTest3";
}
void Widget::slotTest4(QPoint& Qp)
{
qDebug() << "Qp.x()=" << Qp.x() << " Qp.y()=" << Qp.y() << "slotTest4";
}
顺便记录下setGeometry
:
inline void QWidget::setGeometry(int ax, int ay, int aw, int ah)
{ setGeometry(QRect(ax, ay, aw, ah)); }
信号与槽参数不对应,会出现类似如下错误:
QObject::connect: Incompatible sender/receiver arguments
Widget::sigTest(QPoint&) --> Widget::slotTest3(QRect&)
这里我定义的sigTest(QPoint&)
是自定义信号,slotTest3(QRect&)
是自定义槽,因为参数不匹配,所以执行的时候对应的槽函数不会执行。
跨线程信号与槽的连接:
connect(m_thread, &ThreadFromQThread::progress
, this, &Widget::progress);
其中:m_thread = new ThreadFromQThread(this);
,ThreadFromQThread
是继承QObject
的线程类,progress
是线程中的自定义信号,this表示当前对象,也就是Widget
,progress
是当前对象类中的信号。
- 函数功能:
1)Modify
按钮按下之后,触发slotTest1()
槽函数。然后slotTest1()
槽函数会修改lEdit
的值为SIMON
,修改label
的值为TTT
。同时设置QPoint Qp
的值为(10, 10),如果label
的值不是My Label
,就会触发sigTest(Qp)
信号。
2) 信号触发后,对应的槽函数slotTest2(QPoint&)
和slotTest3()
执行,而slotTest3(QRect&)
因为参数错误,不会执行。slotTest2(QPoint&)
执行之后会设置lEdit
的值为signal
,同时打印Qp
的值。slotTest3()
会打印slotTest3
。
总结:
总体来说,Qt的信号与槽设计的简单好用,而且能够跨线程连接信号与槽!或许有更多的细节,比如disconnect
,不过像我这种入门级别的,能够使用就好了。以后继续补充!