57

Boost.Signals允许使用槽的返回值来形成信号的返回值的各种策略。例如添加它们,形成vector它们,或返回最后一个。

普遍的智慧(在 Qt 文档[编辑:以及对此问题的一些答案]中表达)是 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 不仅没有抱怨返回类型为非 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::DirectConnectionQt::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 运行时,它会构造一个测试类。构造函数将两个插槽连接到 testSignal 信号,然后发出信号。它从调用的槽中捕获返回值。

不幸的是,您只能获得最后一个返回值。如果你评估上面的代码,你会得到:“testSlot2”,信号连接槽的最后一个返回值。

这就是为什么。Qt Signals 是信号模式的语法糖接口。插槽是信号的接收者。在直接连接的信号槽关系中,您可以将其视为类似于(伪代码):

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

显然,moc 在这个过程中做了更多的帮助(基本的类型检查等),但这有助于描绘画面。

于 2011-05-05T19:28:31.473 回答
9

不,他们不能。

Boost::signals与Qt中的完全不同。前者提供了高级回调机制,而后者实现了信令习惯。在多线程的上下文中,Qt 的(跨线程)信号依赖于消息队列,因此它们在某些(发射器的线程未知的)时间点被异步调用。

于 2011-04-30T13:57:06.620 回答
1

Qt 的 qt_metacall 函数返回一个整数状态码。正因为如此,我相信这使得实际的返回值变得不可能(除非您在预编译后对元对象系统和 moc 文件进行忽悠)。

但是,您确实可以使用正常的函数参数。应该可以修改您的代码以使用充当“返回”的“输出”参数。

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

Qt signal您可以使用以下代码获得返回值:

我的示例展示了如何使用 aQt signal来读取 a 的文本QLineEdit。我只是在扩展@jordan 的建议:

应该可以修改您的代码以使用充当“返回”的“输出”参数。

#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

您可以尝试使用以下方法解决此问题:

  1. 您所有连接的插槽必须将其结果保存在可从信号对象访问的某个位置(容器)中
  2. 最后一个连接的插槽应该以某种方式(选择最大值或最后一个值)处理收集的值并公开唯一的值
  3. 发射对象可以尝试访问此结果

就像一个想法。

于 2011-04-30T16:09:09.603 回答