Qt的信号和槽机制,使得两个对象可以进行交互。得益于Qt的元对象系统,可以在Qt的help中查找The Meta-Object System,它告诉我们如何使用该系统,进而使用信号和槽以及属性系统。
来自Qt help 文档
The meta-object system is based on three things:
1.The QObject class provides a base class for objects that can take advantage of the meta-object system.
2.The Q_OBJECT macro inside the private section of the class declaration is used to enable meta-object features, such as dynamic properties, signals, and slots.
3.The Meta-Object Compiler (moc) supplies each QObject subclass with the necessary code to implement meta-object features.
我们只需要继承QObject或其子类,并使用宏Q_OBJECT,signals下声明信号,xx slots下声明槽函数即可。
使用时,我们提倡最新的语法,函数指针,而非字符串。
// 1 继承QObject
class Sender:public QObject{
// 2 宏,元对象系统
Q_OBJECT
public:
explicit Sender(QObject *parent = nullptr){}
~Sender(){}
void sendData(){
emit sig_sendData(10);
// emit 关键字为空
sig_sendData("hello");
Data data; data.count = 20; data.str = "good";
emit sig_sendCusData(data);
}
signals:
// 重载
void sig_sendData(int data);
void sig_sendData(QString data);
// 自定义数据
void sig_sendCusData(Data &data);
};
class Geter:public QObject{
Q_OBJECT
public:
explicit Geter(QObject *parent = nullptr){}
~Geter(){}
public slots:
void slot_getData(int data);
void slot_getData(QString data);
void slot_getCusData(Data &data);
private slots:
};
连接
Sender *pSender = new Sender;
Geter *pGeter = new Geter;
connect(pSender, static_cast<void(Sender::*)(int)>(&Sender::sig_sendData),
pGeter, static_cast<void(Geter::*)(int)>(&Geter::slot_getData));
// 使用自定义数据,直连可以的,但是队列时,涉及到copy等操作,需要注册到元系统中
qRegisterMetaType<Data>("Data");
qRegisterMetaType<Data>("Data &");
qRegisterMetaType<Data>("Data *");
connect(pSender, &Sender::sig_sendCusData, pGeter, &Geter::slot_getCusData, Qt::QueuedConnection);
// C++11 lambda
connect(pSender, &Sender::sig_sendCusData, [](Data &data){
// to do
});
// 不仅仅QObject
auto fun = std::function<void(Data)>{
};
connect(pSender, &Sender::sig_sendCusData, fun);
- 信号的重载,使用函数指针转换即可
- 自定义数据类型,qRegisterMetaType<T>("Tname")
- emit 关键字没有非常实用
- 新语法,它可以连接QObject的任何成员方法,不仅仅是定义的槽。lambda,bind,function
- 连接类型,默认AutoConnection。连接的类型确定时机:信号发出。判定规则:接受者所依附的线程和发送者所依附的线程是否相同,相同则直连,否则队列连。槽函数工作的线程:直连时,在信号的发送端;队列连时,在接受端。(个人认为:连接类型不应该人为修改,选择默认的就可以)
(Default) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.
既然使用了qRegisterMetaType,顺带说下Q_DECLARE_METATYPE,这样就可使用Qt的万能数据QVariant了,单这个只是在直连时有效,因此配合qRegisterMetaType使用。
Q_DECLARE_METATYPE声明一个自定义类型时,我们要为该类声明默认构造,拷贝构造,重载等于号,析构函数。eg:
// Creating Custom Qt Types
class CusVar{
public:
CusVar(){}
CusVar(const CusVar &other){info = other.info;}
~CusVar(){}
void operator = (const CusVar &other){
info = other.info;
}
QString getInfo(){return info;}
private:
QString info = "123";
};
Q_DECLARE_METATYPE(CusVar)
在QVariant使用中
QVariant varData;
// default
CusVar var;
// copy
varData.setValue(var);
// default
CusVar getVar;
// copy =
getVar = varData.value<CusVar>();
qDebug() << "get cusVar" << getVar.getInfo();
// copy
CusVar getVarEx = varData.value<CusVar>();
qDebug() << "get cusVarEx" << getVarEx.getInfo();