57

Boost.Signalsは、スロットの戻り値を使用してシグナルの戻り値を形成するさまざまな戦略を可能にします。たとえば、それらを追加したり、それらから を形成しvectorたり、最後のものを返したりします。

一般的な知恵 (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 はここで何をしているのでしょうか。

スロットは戻り値を持つことができるので、戻り値を持つスロットを戻り値を持つシグナルに接続できますか? 結局、それは可能でしょうか?もしそうなら、それは役に立ちますか?

編集:回避策を求めているわけではないので、提供しないでください。

編集:Qt::QueuedConnectionモードでは明らかに役に立ちません(ただし、 QPrintPreviewWidget APIでもありませんが、それでも存在し、有用です)。Qt::DirectConnectionしかし、 and Qt::BlockingQueuedConnection(またはQt::AutoConnectionに解決される場合は) はどうでしょうかQt::DirectConnection

4

5 に答える 5

43

わかった。ということで、もう少し調べてみました。これは可能のようです。信号を発信し、信号が接続されているスロットから値を受け取ることができました。しかし、問題は、複数の接続されたスロットからの最後の戻り値のみを返すことでした:

簡単なクラス定義 ( 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"

main が実行されると、テスト クラスの 1 つが構築されます。コンストラクターは、2 つのスロットを testSignal シグナルに結び付けてから、シグナルを発信します。呼び出されたスロットからの戻り値をキャプチャします。

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

理由は次のとおりです。Qt シグナルは、シグナル パターンへのシンタックス シュガー インターフェイスです。スロットはシグナルの受信者です。直接接続された信号とスロットの関係では、(疑似コード) のように考えることができます。

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

明らかに、moc はこのプロセス (基本的な型チェックなど) を支援するためにもう少し多くのことを行いますが、これは絵を描くのに役立ちます。

于 2011-05-05T19:28:31.473 に答える
9

いいえ、できません。

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

于 2011-04-30T13:57:06.620 に答える
1

Qt signal次のコードで戻り値を取得できます。

私の例は、 a を使用して aQt signalのテキストを読み取る方法を示していますQLineEdit。@jordan が提案したものを拡張しているだけです。

「return」として機能する「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();です。

于 2013-07-18T17:01:21.050 に答える
1

Qt の qt_metacall 関数は、整数のステータス コードを返します。このため、これにより実際の戻り値が不可能になると思います(プリコンパイル後にメタオブジェクトシステムと moc ファイルをいじらない限り)。

ただし、通常の関数パラメーターを自由に使用できます。「return」として機能する「out」パラメーターを使用するようにコードを変更できるはずです。

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

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

// somewhere else in the code...

return_type ret;
emit this->method(&ret);
于 2011-05-05T14:22:02.017 に答える
-1

次の方法でこれを回避できます。

  1. 接続されたすべてのスロットは、シグナル オブジェクトからアクセス可能な場所 (コンテナー) に結果を保存する必要があります。
  2. 最後に接続されたスロットは、何らかの方法で (最大値または最後の値を選択) 収集された値を処理し、1 つだけを公開する必要があります。
  3. 放出オブジェクトは、この結果にアクセスしようとすることができます

あくまでアイデアとして。

于 2011-04-30T16:09:09.603 に答える