Qt signal-slot
阿新 • • 發佈:2019-01-11
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();