Может ли Qt-сигналы вернуть значение?
Boost.Signals позволяет использовать различные страtagsи использования возвращаемых значений слотов для формирования возвращаемого значения сигнала. Например, добавив их, сформировав из них vector
или вернув последний.
Общая мудрость (выраженная в документации Qt [EDIT: а также некоторые ответы на этот вопрос ] ) заключается в том, что с Qt-сигналами такой возможности не существует.
Однако, когда я запускаю moc в следующем определении classа:
- что означает __declspec (dllimport)?
- Как использовать Qt в проектах Visual Studio 2015?
- Подключение перегруженных сигналов и слотов в Qt 5
- Каков наиболее эффективный способ отображения декодированных видеокадров в 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 не жалуется на сигнал с невообразимым возвращаемым типом, он, как представляется, активно реализует его таким образом, чтобы разрешить возвращаемое значение:
// SIGNAL 1 int Object::intSignal() { int _t0; void *_a[] = { const_cast(reinterpret_cast(&_t0)) }; QMetaObject::activate(this, &staticMetaObject, 1, _a); return _t0; }
Итак: согласно документам, эта вещь невозможна. Тогда что делает moc здесь?
Слоты могут иметь возвращаемые значения , поэтому можем ли мы подключить слот с возвращаемым значением к сигналу с возвратным значением сейчас? Может быть, это возможно, в конце концов? Если это так, полезно ли это?
EDIT: Я не прошу обходных решений, поэтому, пожалуйста, не предоставляйте никаких.
EDIT: Очевидно, что это не полезно в режиме Qt::QueuedConnection
(ни API-интерфейс QPrintPreviewWidget , ни все же он существует и полезен). Но как насчет Qt::DirectConnection
и Qt::BlockingQueuedConnection
(или Qt::AutoConnection
, когда он разрешает Qt::DirectConnection
).
- Как включить OpenSSL в проект Qt
- Как скомпилировать Qt 5 под Windows или Linux, 32 или 64 бит, статические или динамические на VS2010, VS2012, VS2013 или VS2015 Express или g ++
- Qt сигнализирует по streamам, один - stream GUI?
- qfiledialog - Фильтрация папок?
- Как эффективно отображать OpenCV-видео в Qt?
- Как использовать идиому PIMPL Qt?
- как преобразовать opencv cv :: Mat в qimage
- Qt Linker Error: «неопределенная ссылка на vtable»
ОК. Итак, я немного поработал. Кажется, это возможно. Я смог испустить сигнал и получить значение из слота, к которому был подключен сигнал. Но проблема заключалась в том, что он возвращал только последнее возвращаемое значение из нескольких подключенных слотов:
Вот простое определение classа ( main.cpp
):
#include #include 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"
При основных запусках он создает один из тестовых classов. Конструктор соединяет два слота с сигналом testSignal, а затем испускает сигнал. Он фиксирует возвращаемое значение из выведенного слота (ов).
К сожалению, вы получите только последнее возвращаемое значение. Если вы оцениваете приведенный выше код, вы получите: «testSlot2», последнее возвращаемое значение из подключенных слотов сигнала.
Вот почему. Qt Signals - это синтаксический сахаризованный интерфейс для шаблона сигнализации. Слоты являются получателями сигнала. В прямом соединении с сигналом-слотом вы можете думать о нем аналогично (псевдокоду):
foreach slot in connectedSlotsForSignal(signal): value = invoke slot with parameters from signal return value
Очевидно, что moc делает немного больше, чтобы помочь в этом процессе (рудиментарная проверка типов и т. Д.), Но это помогает нарисовать картину.
Нет, они не могут.
Boost::signals
сильно отличаются от Boost::signals
в Qt. Первые предоставляют расширенный механизм обратного вызова, тогда как последний реализует сигнальную идиому. В контексте многопоточности сигналы Qt (cross-threaded) зависят от очередей сообщений, поэтому они называются асинхронно на некотором (неизвестном для streamа эмиттера) момент времени.
Функция 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);
Вы можете получить возвращаемое значение из Qt signal
с помощью следующего кода:
В моем примере показано, как использовать Qt signal
для чтения текста QLineEdit
. Я просто расширяю то, что предложил @jordan:
Должна быть возможность изменить свой код таким образом, чтобы использовать параметры «out», которые действуют как ваш «возврат».
#include #include 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();
,
Вы можете попытаться решить эту проблему следующим образом:
- Все подключенные слоты должны сохранять свои результаты в некотором месте (контейнере), доступном из объекта сигнализации
- Последний подключенный слот должен каким-то образом (выбрать максимальное или последнее значение) обрабатывать собранные значения и выставлять только один
- Испускающий объект может попытаться получить доступ к этому результату
Как идея.