2011-04-30 32 views
46

Boost.Signalsは、スロットの戻り値を使用して信号の戻り値を形成するvarious strategiesを許可します。例えば。それらを追加するか、vectorを作成するか、最後のものを返します。Qt信号が値を返すことはできますか?

(Qtのドキュメントで表現[EDIT:だけでなく、この質問にいくつかの答え])共通の知恵はそのような事はQtの信号で可能ではないということです。しかし

、私は次のクラス定義上MOCを実行します。

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はありません、積極的にそれを実装するようですのような方法は、戻り値を通過させる:

// 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; 
} 

ので:ドキュメントによると、このことはできません。では、ここでモックは何をしていますか?

Slots can have return valuesここで、戻り値を持つスロットに戻り値のある信号を接続することはできますか?結局それは可能だろうか?もしそうなら、それは役に立ちますか?

編集:私は回避策を求めていないので、何も提供しないでください。

EDIT:それは明らかに(ただし、QPrintPreviewWidget APIではありません、そしてまだそれが存在すると便利ですどちらも)Qt::QueuedConnectionモードでは有用ではありません。しかし、Qt::DirectConnectionQt::BlockingQueuedConnection(またはQt::AutoConnection、それがQt::DirectConnectionに解決されるとき)についてはどうでしょうか。

答えて

33

OK。だから私はもう少し調査をしました。これは可能です。私は信号を放射することができ、信号が接続されたスロットから値を受け取ることができました。メインの実行、それはテストクラスの1を構成した場合

#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" 

:ここ

は、単純なクラス定義(main.cpp)です。しかし、問題はそれだけで、複数の接続のスロットから最後の戻り値を返したことでした。コンストラクタは、2つのスロットをtestSignal信号に配線し、信号を出力します。呼び出されたスロットからの戻り値を取得します。

残念ながら、最後の戻り値のみを取得します。上記のコードを評価すると、シグナルの接続スロットからの最後の戻り値である "testSlot2"が得られます。

ここに理由があります。 Qt Signalsは、シグナリングパターンへのシンタックススグアードインターフェイスです。スロットは信号の受信者です。直接接続された信号スロットの関係では、あなたは(擬似コード)に似て、それを考えることができます:

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

MOC(初歩的な型チェックを、など)は、このプロセスを支援するためにもう少しを行いますが、これは絵を描くのに役立ちます。

+2

実際にお試しいただきありがとうございます:)私はあなたのコードをより簡単で短く編集しました。しかし、問題は依然として立っている:もしそれが動作する( "最後に呼ばれた"セマンティクスで)、なぜドキュメントはそれがないと言っているのだろうか? –

+0

良い質問です。私はドキュメントは、それが部分的な戻り値であるため動作しないと言います。シグナル排出量*の本当の戻り値は、何らかの種類のアグリゲーターに基づくすべての結果の集計でなければなりません(ブーストのように)。しかし、それがなければ、それは部分的で未定義の結果です(特に、同時シグナル呼び出しの場合)。おそらくコンパイラの違いもありますか? – jsherer

+1

Qt 5.0でまだ動作していないことが保証されていないことを意味します。 – Torp

7

いいえ、できません。

Boost::signalsはQtのものと大きく異なります。前者は高度なコールバックメカニズムを提供し、後者はシグナリングイディオムを実装します。マルチスレッドのコンテキストでは、Qtの(クロススレッド)信号はメッセージキューに依存するため、エミッタのスレッドには未知の時点で非同期的に呼び出されます。

+1

どのように実行時に発生する接続の種類に依存することができますか、それらを使用してコードを記述していますか?これらはテンプレートではなく、Qtは主にランタイムライブラリです:) – vines

+0

[QPrintPreviewWidget :: paintRequested()](http://doc.trolltech.com/latest/qprintpreviewwidget.html#paintRequested)は、まったく悪いAPIだとも考えています。私も。それでも、それはそこにあり、働きます。 –

+0

Qt信号/スロットのメカニズムは非同期でも動作するように設計されているので、これは質問に対する唯一の正解です。 –

-1

次でこれを回避しようとすることができます:

  1. あなたのすべての接続スロットはオブジェクト
  2. のシグナリングからアクセスできるいくつかの場所(コンテナ)で、その結果を保存する必要があり、最後の接続スロットが何らかの形で(最大選択する必要がありますか最後の値)は、プロセスが値を収集し、発光物体がジャストアイデアとして、この結果に

にアクセスしようとすることができます

  • 1のみを公開します。

    +0

    残念ながら、最後に接続されたスロットはどこにあるのかは分かりません。なぜなら、ライブラリーはあなたに指示せず、接続の種類の順序を注意深く制御することによって、最初に信号を使用する目的に反するからです。 –

    +0

    私は回避策を求めていませんでした。私の質問をもう一度お読みください。 –

    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

    1

    次のコードでQt signalからの戻り値を取得することがあります。

    私の例では、QLineEditのテキストを読むためにQt signalを使用する方法を示します。 私はちょうど@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();を要求し、これを使用します。

    関連する問題