C++ Qt 信号可以返回一个值吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5842124/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can Qt signals return a value?
提问by Marc Mutz - mmutz
Boost.Signalsallows various strategiesof using the return values of slots to form the return value of the signal. E.g. adding them, forming a vector
out of them, or returning the last one.
Boost.Signals允许使用槽的返回值来形成信号的返回值的各种策略。例如添加它们,形成一个vector
,或者返回最后一个。
The common wisdom (expressed in the Qt documentation [EDIT:as well as some answers to this question ]) is that no such thing is possible with Qt signals.
常识(在 Qt 文档[编辑:以及对这个问题的一些答案] 中表达)是 Qt 信号不可能做到这一点。
However, when I run the moc on the following class definition:
但是,当我在以下类定义上运行 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();
};
Not only doesn't moc complain about the signal with the non-void return type, it seems to actively implement it in such a way as to allowa return value to pass:
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;
}
So: according to the docs, this thing isn't possible. Then what is moc doing here?
所以:根据文档,这件事是不可能的。那么moc在这里做什么呢?
Slots can have return values, so can we connect a slot with a return value to a signal with a return value now? May that be possible, after all? If so, is it useful?
插槽可以有返回值,那么我们现在可以将带有返回值的插槽连接到带有返回值的信号吗?毕竟这可能吗?如果有,有用吗?
EDIT:I'm not asking for workarounds, so please don't provide any.
编辑:我不是在要求解决方法,所以请不要提供任何解决方法。
EDIT:It obviously isn't useful in Qt::QueuedConnection
mode (neither is the QPrintPreviewWidget API, though, and still it exists and is useful). But what about Qt::DirectConnection
and Qt::BlockingQueuedConnection
(or Qt::AutoConnection
, when it resolves to Qt::DirectConnection
).
编辑:它显然在Qt::QueuedConnection
模式下没有用(虽然QPrintPreviewWidget API也不是,但它仍然存在并且有用)。但是关于Qt::DirectConnection
and Qt::BlockingQueuedConnection
(或者Qt::AutoConnection
,当它解析为 时Qt::DirectConnection
)呢?
采纳答案by jsherer
OK. So, I did a little more investigating. Seems this is possible. I was able to emit a signal, and receive value from the slot the signal was connected to. But, the problem was that it only returned the last return value from the multiple connected slots:
好的。所以,我做了更多的调查。似乎这是可能的。我能够发出信号,并从信号所连接的插槽接收值。但是,问题是它只从多个连接的插槽返回最后一个返回值:
Here's a simple class definition (main.cpp
):
这是一个简单的类定义 ( 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"
When main runs, it constructs one of the test classes. The constructor wires up two slots to the testSignal signal, and then emits the signal. It captures the return value from the slot(s) invoked.
当 main 运行时,它构造一个测试类。构造函数将两个插槽连接到 testSignal 信号,然后发出信号。它从调用的插槽中捕获返回值。
Unfortunately, you only get the last return value. If you evaluate the code above, you'll get: "testSlot2", the last return value from the connected slots of the signal.
不幸的是,您只能获得最后一个返回值。如果你评估上面的代码,你会得到:“testSlot2”,信号的连接槽的最后一个返回值。
Here's why. Qt Signals are a syntax sugared interface to the signaling pattern. Slots are the recipients of a signal. In a direct connected signal-slot relationship, you could think of it similar to (pseudo-code):
这是为什么。Qt 信号是信号模式的语法糖接口。插槽是信号的接收者。在直接连接的信号槽关系中,你可以认为它类似于(伪代码):
foreach slot in connectedSlotsForSignal(signal):
value = invoke slot with parameters from signal
return value
Obviously the moc does a little more to help in this process (rudimentary type checking, etc), but this helps paint the picture.
显然,moc 在这个过程中做了更多的工作(基本的类型检查等),但这有助于描绘画面。
回答by vines
No, they can't.
不,他们不能。
Boost::signals
are quite different from those in Qt. The former provide an advanced callback mechanism, whereas the latter implement the signaling idiom. In the context of multithreading, Qt's (cross-threaded) signals depend on message queues, so they are called asynchronously at some (unknown to the emitter's thread) point in time.
Boost::signals
与 Qt 中的完全不同。前者提供了先进的回调机制,而后者实现了信令习惯用法。在多线程上下文中,Qt 的(跨线程)信号依赖于消息队列,因此它们在某个(发射器的线程未知)时间点被异步调用。
回答by Antonio Dias
You may get a return value from Qt signal
with the following code:
您可以Qt signal
使用以下代码获得返回值:
My example shows how to use a Qt signal
to read the text of a QLineEdit
.
I'm just extending what @jordan has proposed:
我的示例展示了如何使用 aQt signal
读取 a 的文本QLineEdit
。我只是扩展了@jordan 的提议:
It should be possible to modify your code in such a way to use "out" parameters that act as your "return".
应该可以以这样一种方式修改您的代码,以使用充当您的“返回”的“输出”参数。
#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;
};
To use this, just request call();
.
要使用它,只需请求call();
.
回答by jsherer
Qt's qt_metacall function returns an integer status code. Because of this, I believe this makes an actual return value impossible (unless you fudge around with the meta object system and moc files after precompilation).
Qt 的 qt_metacall 函数返回一个整数状态代码。正因为如此,我相信这使得实际的返回值变得不可能(除非你在预编译后使用元对象系统和 moc 文件)。
You do, however, have normal function parameters at your disposal. It should be possible to modify your code in such a way to use "out" parameters that act as your "return".
但是,您确实可以使用正常的函数参数。应该可以以这样一种方式修改您的代码,以使用充当您的“返回”的“输出”参数。
void ClassObj::method(return_type * return_)
{
...
if(return_) *return_ = ...;
}
// somewhere else in the code...
return_type ret;
emit this->method(&ret);
回答by Sergey Leyko
You can try to workaround this with following:
您可以尝试使用以下方法解决此问题:
- All your connected slots must save their results in some place (container) accessible from signaling object
- The last connected slot should somehow (select max or last value) process collected values and expose the only one
- The emitting object can try to access this result
- 所有连接的插槽必须将结果保存在可从信号对象访问的某个地方(容器)
- 最后一个连接的插槽应该以某种方式(选择最大值或最后一个值)处理收集的值并公开唯一的值
- 发射对象可以尝试访问这个结果
Just as an idea.
就像一个想法。