Qt信号可以返回一个值吗?

问题描述 投票:49回答:5

Boost.Signals允许various strategies使用槽的返回值来形成信号的返回值。例如。添加它们,从它们中形成一个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在这做什么?

Slots can have return values,那么我们可以将带有返回值的槽连接到具有返回值的信号吗?毕竟,这可能吗?如果是这样,它有用吗?

编辑:我不是要求解决方法,所以请不要提供任何解决方法。

编辑:它显然在Qt::QueuedConnection模式中没有用(虽然QPrintPreviewWidget API也不是,但它仍然存在并且很有用)。但是Qt::DirectConnectionQt::BlockingQueuedConnection(或Qt::AutoConnection,当它解析为Qt::DirectConnection时)怎么样?

c++ qt return-value signals-slots boost-signals
5个回答
35
投票

好。所以,我做了一些调查。似乎这是可能的。我能够发出信号,并从信号连接的插槽中接收值。但是,问题是它只返回多个连接插槽的最后一个返回值:

这是一个简单的类定义(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信号是信令模式的语法糖界面。插槽是信号的接收者。在直接连接的信号槽关系中,你可以认为它类似于(伪代码):

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

显然,moc在这个过程中做了一点帮助(基本类型检查等),但这有助于绘制图片。


8
投票

不,他们不能。

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


1
投票

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);

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();


-1
投票

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

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

就像一个想法。

© www.soinside.com 2019 - 2024. All rights reserved.