2011-04-30 469 views
46

Boost.Signals允許various strategies使用時隙的返回值來形成信號的返回值。例如。添加它們,形成vector或返回最後一個。Qt信號可以返回一個值嗎?

的共同智慧(Qt文檔所表達[編輯:以及一些這個問題的答案])是沒有這樣的事情是可能的Qt的信號。

然而,當我運行下面的類定義商務部:

class Object : public QObject { 
    Q_OBJECT 
public: 
    explicit Object(QObject * parent=0) 
     : QObject(parent) {} 

public Q_SLOTS: 
    void voidSlot(); 
    int intSlot(); 

Q_SIGNALS: 
    void voidSignal(); 
    int intSignal(); 
}; 

不但沒有MOC抱怨與非void返回類型的信號,似乎要積極落實它在這樣的一種方式,允許返回值傳遞:

// SIGNAL 1 
int Object::intSignal() 
{ 
    int _t0; 
    void *_a[] = { const_cast<void*>(reinterpret_cast<const void*>(&_t0)) }; 
    QMetaObject::activate(this, &staticMetaObject, 1, _a); 
    return _t0; 
} 

所以:根據文檔,這件事情是不可能的。那麼moc在這裏做什麼?

Slots can have return values,那麼我們現在可以將帶有返回值的插槽連接到具有返回值的信號嗎?畢竟這可能嗎?如果是這樣,它有用嗎?

編輯:我不是要求解決方法,所以請不要提供任何。

編輯:它顯然沒有用Qt::QueuedConnection模式(雖然QPrintPreviewWidget API,但它仍然存在和有用)。但是Qt::DirectConnectionQt::BlockingQueuedConnection(或Qt::AutoConnection,解析爲Qt::DirectConnection時)怎麼辦?

回答

33

好的。所以,我做了一些更多的調查。似乎這是可能的。我能夠發出信號,並從信號連接到的插槽接收值。但是,問題是,它只返回從多個連接的插槽,最後返回值:

這裏有一個簡單的類定義(main.cpp):

#include <QObject> 
#include <QDebug> 

class TestClass : public QObject 
{ 
    Q_OBJECT 
public: 
    TestClass(); 

Q_SIGNALS: 
    QString testSignal(); 

public Q_SLOTS: 
    QString testSlot1() { 
     return QLatin1String("testSlot1"); 
    } 
    QString testSlot2() { 
     return QLatin1String("testSlot2"); 
    } 
}; 

TestClass::TestClass() { 
    connect(this, SIGNAL(testSignal()), this, SLOT(testSlot1())); 
    connect(this, SIGNAL(testSignal()), this, SLOT(testSlot2())); 

    QString a = emit testSignal(); 
    qDebug() << a; 
} 

int main() { 
    TestClass a; 
} 

#include "main.moc" 

當主運行時,它構建了測試類。構造函數將兩個插槽連接到testSignal信號,然後發出信號。它捕獲調用的插槽的返回值。

不幸的是,你只能得到最後的返回值。如果你評估上面的代碼,你會得到:「testSlot2」,這是信號連接槽中的最後一個返回值。

這是爲什麼。 Qt Signals是信令模式的語法加糖接口。老虎機是信號的接收者。在直接連接信號槽的關係,你能想到的它類似(僞代碼):

foreach slot in connectedSlotsForSignal(signal): 
    value = invoke slot with parameters from signal 
return value 

顯然商務部確實多了幾分在這個過程中提供幫助(基本的類型檢查,等等),但這有助於畫圖。

+2

感謝您的實際嘗試:)我編輯了您的代碼,使其更簡單。然而,問題仍然存在:如果它起作用(用「最後所謂的」語義),爲什麼文檔說它沒有? – 2011-05-05 19:58:08

+0

一個很好的問題。我會假設文檔說它不起作用,因爲它只是部分返回值。信號發射*的真實返回值*應該是基於某種聚合器的所有結果的總和(如增加)。但是,沒有這一點,這是一個部分和未定義的結果(特別是在併發信號調用的情況下)。也許有一些編譯器的差異呢? – jsherer 2011-05-05 20:51:29

+1

未記錄的行爲意味着你不能保證它仍然工作,比如說Qt 5.0 :) – Torp 2011-08-10 13:28:12

7

不,他們不能。

Boost::signals與Qt中的有很大不同。前者提供先進的回調機制,後者實現信號習慣。在多線程環境中,Qt(交叉線程)信號依賴於消息隊列,因此它們在某些時間點(發射器線程未知)異步調用。

+1

如何依賴連接的類型,這些連接將在運行時發生,而您使用它們編寫代碼?這些不是模板,Qt主要是運行時庫:) – vines 2011-04-30 14:28:31

+0

所以你也認爲[QPrintPreviewWidget :: paintRequested()](http://doc.trolltech.com/latest/qprintpreviewwidget.html#paintRequested)是特別糟糕的API。我也是。儘管如此,它仍然存在,並且有效。 – 2011-04-30 16:20:40

+0

我認爲這是唯一正確答案的問題,因爲Qt信號/插槽機制的設計也是異步工作。 – 2016-09-08 09:02:43

-1

你可以嘗試用以下來解決此:

  1. 所有已連接的插槽必須保存其結果在某些地方(容器)訪問與信令對象
  2. 最後連接的插槽某種程度上應(選擇最多或最後一個值)工藝收集的值並暴露只有一個
  3. 的發射對象可以嘗試訪問此結果

正如一個想法。

+0

不幸的是,你不能分辨哪個是最後一個連接的插槽,因爲庫不會告訴你,並仔細控制連接類型的順序,這首先破壞了使用信號的目的。 – 2011-05-03 13:33:34

+0

我沒有要求解決方法,請重新閱讀我的問題。 – 2011-05-03 15:12:45

0

Qt的qt_metacall函數返回一個整數狀態碼。因此,我相信這會使得實際的返回值不可能實現(除非在預編譯之後使用元對象系統和moc文件)。

但是,您可以使用正常的功能參數。應該可以通過這種方式來修改代碼,以使用充當「返回」的「out」參數。

void ClassObj::method(return_type * return_) 
{ 
    ... 

    if(return_) *return_ = ...; 
} 

// somewhere else in the code... 

return_type ret; 
emit this->method(&ret); 
+0

我相信這將需要一個非異步連接,除非你以某種方式設法在具有更多信號的「未來」對象中進行爭奪。 – jsherer 2011-05-05 14:25:24

1

你可能會從Qt signal返回值用下面的代碼:

我的例子顯示瞭如何使用Qt signal讀取QLineEdit的文本。 我只是擴展@jordan建議的內容:

應該可以通過這種方式修改代碼,以便使用「out」參數作爲「返回」。

#include <QtCore> 
#include <QtGui> 

class SignalsRet : public QObject 
{ 
    Q_OBJECT 

public: 
    SignalsRet() 
    { 
     connect(this, SIGNAL(Get(QString*)), SLOT(GetCurrentThread(QString*)), Qt::DirectConnection); 
     connect(this, SIGNAL(GetFromAnotherThread(QString*)), SLOT(ReadObject(QString*)), Qt::BlockingQueuedConnection); 
     edit.setText("This is a test"); 
    } 

public slots: 
    QString call() 
    { 
     QString text; 
     emit Get(&text); 
     return text; 
    } 

signals: 
    void Get(QString *value); 
    void GetFromAnotherThread(QString *value); 

private slots: 
    void GetCurrentThread(QString *value) 
    { 
     QThread *thread = QThread::currentThread(); 
     QThread *mainthread = this->thread(); 
     if(thread == mainthread) //Signal called from the same thread that SignalsRet class was living 
      ReadObject(value); 
     else //Signal called from another thread 
      emit GetFromAnotherThread(value); 
    } 

    void ReadObject(QString *value) 
    { 
     QString text = edit.text(); 
     *value = text; 
    } 

private: 
    QLineEdit edit; 

}; 

要使用此功能,只是要求call();

相關問題