qt - signal - 我的信號/插槽連接不起作用



qt signal connect type (1)

我反复看到人們有沒有被稱為插槽的問題。 我想收集一些最常見的原因。 所以也許我可以幫助別人,避免很多多餘的問題。

信號/插槽連接不工作的原因是什麼? 如何避免這樣的問題呢?


Answer #1

有一些規則可以使信號和插槽的使用更容易,並涵蓋了連接有缺陷的最常見原因。 如果我忘記了什麼,請告訴我。

1)使用信號和插槽的完整簽名:

代替

connect(that, SIGNAL(mySignal), this, SLOT(mySlot));

connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));

並檢查你的拼寫和大寫。

2)使用現有的過載:

仔細檢查您是否正在使用所需的信號和插槽過載,以及您使用的過載是否存在。

3)您的信號和插槽必須兼容:

這尤其意味著參數必須是相同的類型(引用是可以容忍的)並且具有相同的順序。

編譯時語法也需要相同數量的參數。 舊的運行時語法允許將信號連接到參數較少的插槽。

4)總是檢查連接方法的返回值 (程序員不應該忽略返回值):

代替

connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));

總是使用類似的東西

bool success = connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
Q_ASSERT(success);

或者如果你喜歡拋出一個異常或實現完整的錯誤處理。 你也可以使用這樣的宏:

#ifndef QT_NO_DEBUG
#define CHECK_TRUE(instruction) Q_ASSERT(instruction)
#else
#define CHECK_TRUE(instruction) (instruction)
#endif 

CHECK_TRUE(connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int))));

5)您需要排隊連接的事件循環:

也就是說,當你連接不同線程擁有的兩個對象(所謂的排隊連接)的信號/插槽時,你需要調用exec(); 在插槽的線程!

事件循環也需要實際服務。 只要插槽的線程卡在某種繁忙的循環中,就不會執行排隊的連接!

6)您需要為排隊連接註冊自定義類型:

所以在排隊連接中使用自定義類型時,您必須為此註冊它們。

首先使用下面的宏聲明類型:

Q_DECLARE_METATYPE(MyType)

然後使用以下調用之一:

qRegisterMetaType<MyTypedefType>("MyTypedefType"); // For typedef defined types
qRegisterMetaType<MyType>(); // For other types

7)優先使用舊的運行時檢查語法的新的編譯時語法:

代替

connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));

使用這個語法

connect(that, &ThatObject::mySignal, this, &ThisObject::mySlot));

它在編譯期間檢查信號和時隙,甚至不需要目的地是實際的時隙。

如果你的信號被重載,使用下面的語法:

connect(that, static_cast<void (ThatObject::*)(int)> &ThatObject::mySignal), this, &ThisObject::mySlot); // <Qt5.7
connect(that, qOverload<int>::of(&ThatObject::mySignal), this, &ThisObject::mySlot); // >=Qt5.7 & C++11
connect(that, qOverload<int>(&ThatObject::mySignal), this, &ThisObject::mySlot); // >=Qt5.7 & C++14

也不要混合該語法的常量/非常量信號/插槽(通常信號和插槽將是非常量)。

8)你的類需要一個Q_OBJECT宏:

在你使用“signals”和“slots”規範的類中,你需要添加一個如下的Q_OBJECT宏:

class SomeClass
{
   Q_OBJECT

signals:
   void MySignal(int x);
};

class SomeMoreClass
{
   Q_OBJECT

public slots:
   void MySlot(int x);
};

這個宏為這個類添加了必要的元信息。

9)你的物體必須活著:

只要發送者對像或接收者對像被銷毀,Qt就會自動丟棄連接。

如果信號沒有發出:發送者對像是否仍然存在? 如果插槽未被調用:接收器對像是否仍然存在?

要檢查兩個對象的生命週期,在構造器/析構函數中使用一個調試器斷點或一些qDebug()輸出。

10)它仍然不起作用:

要做一個非常快速和骯髒的檢查你的連接發出的信號由你自己使用一些虛擬參數,看看是否被稱為:

connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
emit that->mySignal(0); // Ugly, don't forget to remove it immediately

最後當然有可能是信號不發射。 如果你遵循上面的規則,你的程序的邏輯可能有些錯誤。 閱讀文檔。 使用調試器。 如果現在有其他的方法,請通過詢問。





qt-connection