前言
本文讨论的qt版本只限于qt5及以上,且代码并不保证可运行,仅起示范作用。
使用
qt关键字:signals、emit、slots
下面从一个简单实例总结一些使用注意事项:
class Test : public QObject
{
Q_OBJECT
Test();
~Test(){}
private slots:
void sltTest(int);
signals:
void sglTest(int);
}
Test::Test(){}
void Test::sltTest(int v){}
int main()
{
Test t;
connect(t, &Test::sglTest, t, &Test::sltTest);
emit t->sglTest();
return 0;
}
注意事项:
- 类需要继承了QObject、类声明中需要Q_OBJECT宏
- 信号与槽需要QObject::connect 连接
- 通常情况下信号与槽的参数个数、类型一致
- 信号和槽函数参数都可以有默认值
- 信号:
- 返回值只能是void类型
- 只需要声明,定义由moc生成
- signals前不能有访问控制符,public等
- 信号函数参数个数不能少于槽函数参数个数,槽函数的可以少于信号函数的,
- 关键字冲突
- .pro添加 CONFIG += no_keywords,qt将不定义signals等关键字,可以用Q_SIGNAL替代使用
connect的几种写法
Counter a, b;
//1.推荐写法,使用函数指针可以不用写参数,编译器会检查函数签名,隐式转换参数类型,避免同名函数歧义问题
QObject::connect(&a, &Counter::valueChanged, &b, &Counter::setValue);
//2.使用SIGNAL and SLOT宏,不会检查函数签名,不允许有参数名,不能有返回类型,
QObject::connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int)));
//3.lambda表达式
connect(&a, &a::valueChanged, this, [=](int v){ });
连接类型
AutoConnection,发送和接收在同一线程,则是DirectConnection,否则QueuedConnection
DirectConnection,直接调用槽函数,类似调用普通函数,在信号所在线程中执行
QueuedConnection,队列关联,当控制权回到接收线程的事件循环时被调用
BlockingQueuedConnection,阻塞队列关联,类似队列关联,只是信号线程会阻塞到槽函数返回,所以不可用于信号和接收者同一线程,将会导致死锁。
UniqueConnection,唯一关联,标志位,可与上类型组合使用,已存在的连接将会连接失败
疑问
- 同名函数,不同参数类型,connect?。编译报错:上下文不允许消除重载函数的歧义, error C2664: “QMetaObject::Connection QObject::connect(const QObject *,const char *,const QObject *,const char *,Qt::ConnectionType)”: 无法将参数 2 从“overloaded-function”转换为“const char *”
需要明确指出函数,指定函数指针参数类型即可
void (TestSlot::*newSgl)(int) = &TestSlot::sglTest;
void (TestSlot::*newSlt)(int) = &TestSlot::sltTest;
或者
static_cast<void (TestSlot:: *)(int)>(&TestSlot::sglTest)
或者typedef xx xxx
- 信号槽的执行顺序?
注意qt版本的不同,qt4应该是随机的,qt5之后按连接顺序执行。备注:未经详细测试
connect: signal a -> slot a signal a -> slot b signal a -> slot c, 顺序:a -> b -> c。
参考
官网:https://doc.qt.io/qt-5/signalsandslots.html
使用及一些注意和原理讲解:https://zhuanlan.zhihu.com/p/347456731