Weird issue with SIGNAL/SLOT
-
Hi,
I've been using signal and slots mostly between processes running under multiple threads but now I'm try instantiate two classes under a signal thread and using signal/slot to communicate between them. But for some reason the slot from one object is not being received from the other. Here is an example.I'm creating a thread in a class:
#include "PluginWorker.h" void StartThread::startThread() { std::cout << "STARTING THREAD" << std::endl; QThread* pluginWorkerThread = new QThread; pluginWorkerThread->setObjectName("pluginWorkerThread"); PluginWorker *pluginWorker = new PluginWorker; pluginWorker->moveToThread(pluginWorkerThread); connect(pluginWorker, SIGNAL(finished()), pluginWorkerThread, SLOT(quit())); connect(pluginWorker, SIGNAL(finished()), pluginWorker, SLOT(deleteLater())); connect(pluginWorkerThread, SIGNAL(finished()), pluginWorkerThread, SLOT(deleteLater())); connect(this, SIGNAL(sendExit()), pluginWorker, SLOT(receiveExit()), Qt::DirectConnection); pluginWorkerThread->start(); }
Once the thread is started using this call from another class
startThread_ = new StartThread(); startThread_->startThread();
The thread does indeed start so far it is ok.
In the pluginWorker class which runs under the above thread, I instantiate 2 classes as follows:PluginWorker::PluginWorker() : selectdatabase_(nullptr) ,databaseProcessing_(nullptr) { std::cout << "STARTING PLUGIN WORKER" << std::endl; databaseProcessing_ = new DatabaseProcessing(); selectdatabase_ = new SelectDatabase(); //setup communication between selectdatabase_ and databaseProcessing_ connect(selectdatabase_, SIGNAL(sendDatabaseName(QString)), databaseProcessing_, SLOT(getDatabaseName(QString))); }
However when I emit from selectDatabase::sendDatabaseName to the slot in databaseProcessing::getDatabaseName nothing is received.
I'm using Q_Object in both classes for selectDatabase_ and databaseProcessing_
Below is a include example, both are similar:
#ifndef DATBASEPROCESSING_H #define DATBASEPROCESSING_H #include <QObject> #include <QMainWindow> class DatabaseProcessing : public QObject { Q_OBJECT public: DatabaseProcessing(); virtual ~DatabaseProcessing(); public Q_SLOTS: void getDatabaseName(QString databaseName); };
Would anyone have any idea why the slot is not being called? I really would appreciate any feedback.
Thanks!
-
@leinad
This was just the first step. Now we know the signal does get emitted and theconnect()
attaches to it.Now:
connect(selectdatabase_, &SelectDatabase::sendDatabaseName, databaseProcessing_, &DatabaseProcessing::getDatabaseName)
(Put a
qDebug() << databaseName;
as first statement in slot.) I presume you will say the slot does not get called?If not, are
selectdatabase_
anddatabaseProcessing_
in different threads? If so, do you allow the event loop to run (signals across threads are queued)? -
Hi,
I've been using signal and slots mostly between processes running under multiple threads but now I'm try instantiate two classes under a signal thread and using signal/slot to communicate between them. But for some reason the slot from one object is not being received from the other. Here is an example.I'm creating a thread in a class:
#include "PluginWorker.h" void StartThread::startThread() { std::cout << "STARTING THREAD" << std::endl; QThread* pluginWorkerThread = new QThread; pluginWorkerThread->setObjectName("pluginWorkerThread"); PluginWorker *pluginWorker = new PluginWorker; pluginWorker->moveToThread(pluginWorkerThread); connect(pluginWorker, SIGNAL(finished()), pluginWorkerThread, SLOT(quit())); connect(pluginWorker, SIGNAL(finished()), pluginWorker, SLOT(deleteLater())); connect(pluginWorkerThread, SIGNAL(finished()), pluginWorkerThread, SLOT(deleteLater())); connect(this, SIGNAL(sendExit()), pluginWorker, SLOT(receiveExit()), Qt::DirectConnection); pluginWorkerThread->start(); }
Once the thread is started using this call from another class
startThread_ = new StartThread(); startThread_->startThread();
The thread does indeed start so far it is ok.
In the pluginWorker class which runs under the above thread, I instantiate 2 classes as follows:PluginWorker::PluginWorker() : selectdatabase_(nullptr) ,databaseProcessing_(nullptr) { std::cout << "STARTING PLUGIN WORKER" << std::endl; databaseProcessing_ = new DatabaseProcessing(); selectdatabase_ = new SelectDatabase(); //setup communication between selectdatabase_ and databaseProcessing_ connect(selectdatabase_, SIGNAL(sendDatabaseName(QString)), databaseProcessing_, SLOT(getDatabaseName(QString))); }
However when I emit from selectDatabase::sendDatabaseName to the slot in databaseProcessing::getDatabaseName nothing is received.
I'm using Q_Object in both classes for selectDatabase_ and databaseProcessing_
Below is a include example, both are similar:
#ifndef DATBASEPROCESSING_H #define DATBASEPROCESSING_H #include <QObject> #include <QMainWindow> class DatabaseProcessing : public QObject { Q_OBJECT public: DatabaseProcessing(); virtual ~DatabaseProcessing(); public Q_SLOTS: void getDatabaseName(QString databaseName); };
Would anyone have any idea why the slot is not being called? I really would appreciate any feedback.
Thanks!
@leinad
Hi. I see you have posted quite a lot in this forum. Would you care to start marking your code blocks inside the forum's Code tags? It's the icon which looks like</>
, or put a line of```
(3 backticks) above and below your blocks. You could edit your post. For my part it would make it a lot easier to see what's going on in your post.However when I emit from selectDatabase::sendDatabaseName to the slot in databaseProcessing::getDatabaseName nothing is received.
Why don't you start by connecting a lambda to the signal so that you know that it's being emitted?
-
@leinad
Hi. I see you have posted quite a lot in this forum. Would you care to start marking your code blocks inside the forum's Code tags? It's the icon which looks like</>
, or put a line of```
(3 backticks) above and below your blocks. You could edit your post. For my part it would make it a lot easier to see what's going on in your post.However when I emit from selectDatabase::sendDatabaseName to the slot in databaseProcessing::getDatabaseName nothing is received.
Why don't you start by connecting a lambda to the signal so that you know that it's being emitted?
-
@JonB Sorry. I fixed using the back tics. Can you explain how I can connect a lambda to the signal?
-
@JonB Sorry. I fixed using the back tics. Can you explain how I can connect a lambda to the signal?
@leinad
That's much more readable, thank you :)I didn't want to bring this up, because it likely has nothing to do with your issue, but
SIGNAL
/SLOT()
macros are the old style of Qtconnect()
s. Unfortunately a lot of examples on the web still use them. The new style was introduced a decade ago as C++ supported it. It is type-safe and gives compile time errors if the slot is not right for the signal.connect(signalObject, &SignalClass::method, slotObject, &SlotClass::method);
So for your
connect(selectdatabase_, SIGNAL(sendDatabaseName(QString)), databaseProcessing_, SLOT(getDatabaseName(QString)));
:connect(selectdatabase_, &SelectDatabase::sendDatabaseName, databaseProcessing_, &DatabaseProcessing::getDatabaseName);
Doesn't that look tidier? :) I really suggest you change to this syntax from now onwards.
You need new-style to use C++ lambdas for the slot. I suggest you try something like:
connect(selectdatabase_, &SelectDatabase::sendDatabaseName, databaseProcessing_, [](QString databaseName) { qDebug() << "sendDatabaseName" << databaseName; } );
Now we know whether signal is emitted and passes database name. Does this work?
-
@leinad
That's much more readable, thank you :)I didn't want to bring this up, because it likely has nothing to do with your issue, but
SIGNAL
/SLOT()
macros are the old style of Qtconnect()
s. Unfortunately a lot of examples on the web still use them. The new style was introduced a decade ago as C++ supported it. It is type-safe and gives compile time errors if the slot is not right for the signal.connect(signalObject, &SignalClass::method, slotObject, &SlotClass::method);
So for your
connect(selectdatabase_, SIGNAL(sendDatabaseName(QString)), databaseProcessing_, SLOT(getDatabaseName(QString)));
:connect(selectdatabase_, &SelectDatabase::sendDatabaseName, databaseProcessing_, &DatabaseProcessing::getDatabaseName);
Doesn't that look tidier? :) I really suggest you change to this syntax from now onwards.
You need new-style to use C++ lambdas for the slot. I suggest you try something like:
connect(selectdatabase_, &SelectDatabase::sendDatabaseName, databaseProcessing_, [](QString databaseName) { qDebug() << "sendDatabaseName" << databaseName; } );
Now we know whether signal is emitted and passes database name. Does this work?
-
@leinad
That's much more readable, thank you :)I didn't want to bring this up, because it likely has nothing to do with your issue, but
SIGNAL
/SLOT()
macros are the old style of Qtconnect()
s. Unfortunately a lot of examples on the web still use them. The new style was introduced a decade ago as C++ supported it. It is type-safe and gives compile time errors if the slot is not right for the signal.connect(signalObject, &SignalClass::method, slotObject, &SlotClass::method);
So for your
connect(selectdatabase_, SIGNAL(sendDatabaseName(QString)), databaseProcessing_, SLOT(getDatabaseName(QString)));
:connect(selectdatabase_, &SelectDatabase::sendDatabaseName, databaseProcessing_, &DatabaseProcessing::getDatabaseName);
Doesn't that look tidier? :) I really suggest you change to this syntax from now onwards.
You need new-style to use C++ lambdas for the slot. I suggest you try something like:
connect(selectdatabase_, &SelectDatabase::sendDatabaseName, databaseProcessing_, [](QString databaseName) { qDebug() << "sendDatabaseName" << databaseName; } );
Now we know whether signal is emitted and passes database name. Does this work?
-
@JonB said in Weird issue with SIGNAL/SLOT:
connect(signalObject, &SignalClass::method, slotObject, &SlotClass::method);
Funny, I use QtCreator with TIDY and it never called it out as a bad style. Perhaps the default options disable it?
connect(selectdatabase_, &SelectDatabase::sendDatabaseName, databaseProcessing_, [](QString databaseName) { qDebug() << "sendDatabaseName" << databaseName; } );
I'm afraid I can't use this lambda function because I don't have access to databaseName, it is a QString which is sent from another object outside of the connect class.
-
connect(selectdatabase_, &SelectDatabase::sendDatabaseName, databaseProcessing_, [](QString databaseName) { qDebug() << "sendDatabaseName" << databaseName; } );
I'm afraid I can't use this lambda function because I don't have access to databaseName, it is a QString which is sent from another object outside of the connect class.
-
@leinad
So it appears that the lambda does indeed show the correct value passed but yet the SLOT does not show it :(@leinad
This was just the first step. Now we know the signal does get emitted and theconnect()
attaches to it.Now:
connect(selectdatabase_, &SelectDatabase::sendDatabaseName, databaseProcessing_, &DatabaseProcessing::getDatabaseName)
(Put a
qDebug() << databaseName;
as first statement in slot.) I presume you will say the slot does not get called?If not, are
selectdatabase_
anddatabaseProcessing_
in different threads? If so, do you allow the event loop to run (signals across threads are queued)? -
@leinad
This was just the first step. Now we know the signal does get emitted and theconnect()
attaches to it.Now:
connect(selectdatabase_, &SelectDatabase::sendDatabaseName, databaseProcessing_, &DatabaseProcessing::getDatabaseName)
(Put a
qDebug() << databaseName;
as first statement in slot.) I presume you will say the slot does not get called?If not, are
selectdatabase_
anddatabaseProcessing_
in different threads? If so, do you allow the event loop to run (signals across threads are queued)? -