Standard C++ callbacks handling inside Qt application
-
wrote on 8 Dec 2022, 12:46 last edited by Dragoon 12 Aug 2022, 12:49
Hi I'm a newbie in Qt and I got stuck into a problem I'm not able to handle, I'm using an external library that implements some feature trough callbacks.
AFAIK this llibrary uses different threads to manage such callback. As a result I'm not able to manage such calls:void MainWindow::connectMAV() { mavsdk::ConnectionResult conn_result = mavsdk.add_any_connection("localhost:5000"); setWindowTitle("Listening"); mavsdk.subscribe_on_new_system ( [&]() { setWindowTitle("Connected"); system = mavsdk.systems()[0]; } ); }
In the above code the internal lambda function is never called.
On identical non Qt C++ application the callback is triggered correctly.
I think the problem is the interaction with the event loop management of Qt.
There's a workaround?Best regards,
Mike -
wrote on 26 Jan 2023, 14:24 last edited by Dragoon
it seems that I found the real issue...
I need to put these lines:Q_DECLARE_METATYPE(MissionRawServer::Result) Q_DECLARE_METATYPE(MissionRawServer::MissionPlan)
in my class header
and these:
qRegisterMetaType<MissionRawServer::Result>(); qRegisterMetaType<MissionRawServer::MissionPlan>();
prior connect calls.
Probably since parameters on callback where not QObject derivative they needed to be registered to be connect proof.
I don't know it this's the correct register procedure and explanation of this issue but now ti seem to be fixed.
Could someone confirm? -
Hi I'm a newbie in Qt and I got stuck into a problem I'm not able to handle, I'm using an external library that implements some feature trough callbacks.
AFAIK this llibrary uses different threads to manage such callback. As a result I'm not able to manage such calls:void MainWindow::connectMAV() { mavsdk::ConnectionResult conn_result = mavsdk.add_any_connection("localhost:5000"); setWindowTitle("Listening"); mavsdk.subscribe_on_new_system ( [&]() { setWindowTitle("Connected"); system = mavsdk.systems()[0]; } ); }
In the above code the internal lambda function is never called.
On identical non Qt C++ application the callback is triggered correctly.
I think the problem is the interaction with the event loop management of Qt.
There's a workaround?Best regards,
Mikewrote on 8 Dec 2022, 12:53 last edited by@Dragoon
I don't see how anyone will know what issue there might be in your code or Qt's with some third-party library.Although you say the lambda is never called, if it were and you say it comes from another thread in Qt you would not be allowed to perform
setWindowTitle("Connected")
from a non-UI thread. -
@Dragoon
I don't see how anyone will know what issue there might be in your code or Qt's with some third-party library.Although you say the lambda is never called, if it were and you say it comes from another thread in Qt you would not be allowed to perform
setWindowTitle("Connected")
from a non-UI thread. -
wrote on 8 Dec 2022, 19:25 last edited by
I'm not sure how this would work with a lambda. You might try to create a static member function and pass a pointer to that function. With a static function, you are going to need a pointer to mainWindow, since you wont get "this". A lot of libraries that use callbacks allow you to pass a pointer to "this" as a void * argument for just this purpose.
i.e.
MainWindow.hstatic void onNewSystem();
MainWindow.cpp
mavsdk.subscribe_on_new_system(&MainWindow::onNewSystem); MainWindow::onNewSystem() { // assume that a pointer to MainWindow is set somewhere mainWindow->setWindowTitle("Connected.");
-
Hi I'm a newbie in Qt and I got stuck into a problem I'm not able to handle, I'm using an external library that implements some feature trough callbacks.
AFAIK this llibrary uses different threads to manage such callback. As a result I'm not able to manage such calls:void MainWindow::connectMAV() { mavsdk::ConnectionResult conn_result = mavsdk.add_any_connection("localhost:5000"); setWindowTitle("Listening"); mavsdk.subscribe_on_new_system ( [&]() { setWindowTitle("Connected"); system = mavsdk.systems()[0]; } ); }
In the above code the internal lambda function is never called.
On identical non Qt C++ application the callback is triggered correctly.
I think the problem is the interaction with the event loop management of Qt.
There's a workaround?Best regards,
Mikewrote on 9 Dec 2022, 09:58 last edited by@Dragoon said in Standard C++ callbacks handling inside Qt application:
AFAIK this llibrary uses different threads to manage such callback.
This might be one more problem. You need to call
setWindowTitle()
within the main GUI thread. In addition to previous fixes suggested, why don't you just write to the console if your lambda function gets called? Because it might actually be called but not do what you expect.The easiest way to have something done in the GUI thread is for your callback to just trigger a signal which is connected to a slot that does the actual work (i.e. call
setWindowTitle()
). -
@Dragoon said in Standard C++ callbacks handling inside Qt application:
AFAIK this llibrary uses different threads to manage such callback.
This might be one more problem. You need to call
setWindowTitle()
within the main GUI thread. In addition to previous fixes suggested, why don't you just write to the console if your lambda function gets called? Because it might actually be called but not do what you expect.The easiest way to have something done in the GUI thread is for your callback to just trigger a signal which is connected to a slot that does the actual work (i.e. call
setWindowTitle()
).wrote on 10 Dec 2022, 17:27 last edited by@SimonSchroeder I'll try this approach...
-
@SimonSchroeder I'll try this approach...
wrote on 26 Jan 2023, 12:36 last edited by Dragoon@SimonSchroeder tried and failed.
missionServer->subscribe_incoming_mission( [&](mavsdk::MissionRawServer::Result result, mavsdk::MissionRawServer::MissionPlan plan) { emit incomingMission(result, plan); } ); void MainWindow::onIncomingMission(MissionRawServer::Result result, MissionRawServer::MissionPlan plan) { Q_UNUSED(result); Q_UNUSED(plan); missions++; }
Debugging it I can see callback being triggered but incominMission() never being fired.
-
@Dragoon
I don't see how anyone will know what issue there might be in your code or Qt's with some third-party library.Although you say the lambda is never called, if it were and you say it comes from another thread in Qt you would not be allowed to perform
setWindowTitle("Connected")
from a non-UI thread. -
@JonB the third party library could not be the main issue in this. The problem is the management of C++ 17 standard callbacks.
And, BTW, even:missions++;
(being mission an int variable) is never executed.
@Dragoon Did you make sure you connected incomingMission successfully to onIncomingMission? Did you check the lifetime of the involved objects? If the lambda is called then the signal is for sure emitted. Most probably you did not connect signal/slot.
-
I'm not sure how this would work with a lambda. You might try to create a static member function and pass a pointer to that function. With a static function, you are going to need a pointer to mainWindow, since you wont get "this". A lot of libraries that use callbacks allow you to pass a pointer to "this" as a void * argument for just this purpose.
i.e.
MainWindow.hstatic void onNewSystem();
MainWindow.cpp
mavsdk.subscribe_on_new_system(&MainWindow::onNewSystem); MainWindow::onNewSystem() { // assume that a pointer to MainWindow is set somewhere mainWindow->setWindowTitle("Connected.");
wrote on 26 Jan 2023, 13:09 last edited by@mranger90
defining 'slots' as static member seem to work.
The problem now is to access MainWindow instance... -
@mranger90
defining 'slots' as static member seem to work.
The problem now is to access MainWindow instance...@Dragoon said in Standard C++ callbacks handling inside Qt application:
defining 'slots' as static member seem to work
Why static?!
Can you show how and what you're actually connecting? -
@Dragoon Did you make sure you connected incomingMission successfully to onIncomingMission? Did you check the lifetime of the involved objects? If the lambda is called then the signal is for sure emitted. Most probably you did not connect signal/slot.
wrote on 26 Jan 2023, 13:29 last edited by Dragoon@jsulm said in Standard C++ callbacks handling inside Qt application:
Most probably you did not connect signal/slot.
I'm not SO newbie... ;-)
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , configuration(Mavsdk::Configuration::UsageType::Autopilot) , eventTimer(new QTimer(this)) { ui->setupUi(this); connect(this, &MainWindow::newSystem, this, &MainWindow::onNewSystem); connect(this, &MainWindow::incomingMission, this, &MainWindow::onIncomingMission); connect(eventTimer, &QTimer::timeout, this, &MainWindow::onUpdateEvent); initMAVSDK(); initMAVConnection(); } void MainWindow::initMAVSDK() { configuration.set_system_id(DEF_ID); mavsdk.set_configuration(configuration); } void MainWindow::initMAVConnection() { ConnectionResult conn_result = mavsdk.add_any_connection(DEF_URL.toStdString()); if(conn_result == mavsdk::ConnectionResult::Success) { mavsdk.subscribe_on_new_system( [&](){ emit newSystem(); } ); eventTimer->start(DEF_UPDATE_TIMEOUT); } }
-
wrote on 26 Jan 2023, 14:24 last edited by Dragoon
it seems that I found the real issue...
I need to put these lines:Q_DECLARE_METATYPE(MissionRawServer::Result) Q_DECLARE_METATYPE(MissionRawServer::MissionPlan)
in my class header
and these:
qRegisterMetaType<MissionRawServer::Result>(); qRegisterMetaType<MissionRawServer::MissionPlan>();
prior connect calls.
Probably since parameters on callback where not QObject derivative they needed to be registered to be connect proof.
I don't know it this's the correct register procedure and explanation of this issue but now ti seem to be fixed.
Could someone confirm? -
it seems that I found the real issue...
I need to put these lines:Q_DECLARE_METATYPE(MissionRawServer::Result) Q_DECLARE_METATYPE(MissionRawServer::MissionPlan)
in my class header
and these:
qRegisterMetaType<MissionRawServer::Result>(); qRegisterMetaType<MissionRawServer::MissionPlan>();
prior connect calls.
Probably since parameters on callback where not QObject derivative they needed to be registered to be connect proof.
I don't know it this's the correct register procedure and explanation of this issue but now ti seem to be fixed.
Could someone confirm?@Dragoon said in Standard C++ callbacks handling inside Qt application:
I need to put these lines
Ah, yes you're right. If you use your own custom data types as parameters for signals/slots you have to register them.
-
wrote on 26 Jan 2023, 15:17 last edited by
@Dragoon so should this be marked as solved?
-
@Dragoon so should this be marked as solved?
wrote on 26 Jan 2023, 15:33 last edited by@Kent-Dorfman I do.