How to share one signal for two slots.
-
I have a class with a signal in it
class MyUDP : public QObject { Q_OBJECT public: explicit MyUDP(QObject *parent = nullptr); void Send(QString data, QString remote_ip, quint16 remote_port); void Start(QString ip, quint16 port); QByteArray udp_buffer; bool connect_status; signals: void GetUdpMessage(const SENS_NET_PARAM& param, const QByteArray data); public slots: void ReadyRead(); private: QUdpSocket *socket; };
In mainwindow.h I declare a public instanse of the previous class and a slot
class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); bool eventFilter(QObject *obj, QEvent *event); MyUDP wifi_udp; public slots: void GetUdpMessage(const SENS_NET_PARAM& param, const QByteArray data); //and so on..... }
in mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); ui->tabWidget->setCurrentIndex(0); ui->textEditTerminalTx->installEventFilter(this); QObject::connect(&wifi_udp, &MyUDP::GetUdpMessage, this, &MainWindow::GetUdpMessage); }
and in main.cpp
MainWindow w; w.show();
And I see the message in GUI.
Now I want to parse this message and I created a message parser class with the same slot. But how do I share the instance MyUDP wifi_udp?
When I doextern MyUDP wifi_udp;
I get
error: undefined reference to `wifi_udp'
What do I miss? -
@jenya7 said in How to share one signal for two slots.:
When I do
extern MyUDP wifi_udp;What is this? This made no sense to me!
Where is
wifi_udp
defined?Please take time to understand C++ basics and variable scope and life-cycle is one of them:
- https://www.tutorialspoint.com/cplusplus/cpp_variable_scope.htm
- https://www.geeksforgeeks.org/scope-of-variables-in-c/
- there are many more available on internet
Do not mix-up AINSI-C and C++ concept.
-
@KroMignon said in How to share one signal for two slots.:
@jenya7 said in How to share one signal for two slots.:
When I do
extern MyUDP wifi_udp;What is this? This made no sense to me!
Where is
wifi_udp
defined?In mainwindow.h. Please see above. I explicitly explained it.
@KroMignon said in How to share one signal for two slots.:
@jenya7 said in How to share one signal for two slots.:
When I do
extern MyUDP wifi_udp;Please take time to understand C++ basics and variable scope and life-cycle is one of them:
Do not mix-up AINSI-C and C++ concept.In IAR extern works perfectly well. in any file it can link to a public variable/object.
-
@jenya7 said in How to share one signal for two slots.:
In mainwindow.h. Please see above. I explicitly explained it.
No you did not.
There is a public class attribute
wifi_udp
in classMainWindow
.
So you could access this attribute with:MainWindow w; qDebug() << w.wifi_udp;
But
extern MyUDP wifi_udp;
is a non sense. Has nothing to do with C++ -
@ChrisW67 said in How to share one signal for two slots.:
Where is an instance of your parser class created and how are you trying to connect to it?
msgparser.h
class MSGPARSER : public QObject { Q_OBJECT public: MSGPARSER(QObject *parent = nullptr); uint32_t ParseMessage(char *str); uint32_t ParseMessage(QByteArray data, MESSAGE * sens_msg); MESSAGE sensor_message; public slots: void GetUdpMessage(const SENS_NET_PARAM& param, const QByteArray data); signals: void NewMessageReady(MESSAGE msg); public slots: void GetUdpMessage(const SENS_NET_PARAM& param, const QByteArray data); };
msgparser.cpp
extern MyUDP wifi_udp; //here I get a compile time error MSGPARSER::MSGPARSER(QObject *parent) : QObject(parent) { QObject::connect(&wifi_udp, &MyUDP::GetUdpMessage, this, &MSGPARSER::GetUdpMessage); }
-
@jenya7 said in How to share one signal for two slots.:
main.cpp
int main(int argc, char *argv[]) { MSGPARSER m_msgparser; MainWindow w; w.show(); }
msgparser.cpp
extern MyUDP wifi_udp; //here I get a compile time error MSGPARSER::MSGPARSER(QObject *parent) : QObject(parent) { QObject::connect(&wifi_udp, &MyUDP::GetUdpMessage, this, &MSGPARSER::GetUdpMessage); }
How do you expect this to work?
Please understand thatMyUDP wifi_udp;
does NOT exist ==> MyUDP wifi_udp != MainWindow::wifi_udpThis can work:
- remove the connect in MSGPARSER constructor
- add
QObject::connect(&w.wifi_udp, &MyUDP::GetUdpMessage, &m_msgparser, &MSGPARSER::GetUdpMessage);
in main().
-
OK. With the objects like that you can connect them to each other in main(), where you have visibility of both. You need a pointer to both objects, and that will be awkward the way you have structured this. Something like this should fly (without the extern stuff).
int main(int argc, char *argv[]) { MSGPARSER m_msgparser; MainWindow w; w.show(); QObject::connect( &(w.wifi_udp), &MyUDP::GetUdpMessage, &m_msgparser, &MSGPARSER::GetUdpMessage ); // I assume you deliberately left the rest out. }
Really though you would be cleaner to have MainWindow own both objects:
private: // probably MyUDP *wifi_udp; MSGPARSER *m_msgparser; // Then create and connect the two objects in the MainWindow constructor MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); ui->tabWidget->setCurrentIndex(0); ui->textEditTerminalTx->installEventFilter(this); wifi_udp = new MyUDP(this); m_msgparser = mew MSGPARSER(this); connect(wifi_udp, &MyUDP::GetUdpMessage, this, &MainWindow::GetUdpMessage); connect(wifi_udp, &MyUDP::GetUdpMessage, m_msgparser, &MSGPARSER::GetUdpMessage); }
-
-
I'd like to understand the whole concept.
My algorithm- Get a UDP message.
- Show a UDP message. (udp signal - main window slot)
Parse a UDP message. (udp signal - parser slot) - Put a parsed message in an array (parser signal - sensor class slot)
Everything connected in signal - slot paradigm?
-
@jenya7 said in How to share one signal for two slots.:
I'd like to understand the whole concept.
My algorithm- Get a UDP message.
- Show a UDP message. (udp signal - main window slot)
Parse a UDP message. (udp signal - parser slot)
3.Put a parsed message in an array (parser signal - sensor class slot)
Everything connected in signal - slot paradigm?
Sorry but I don't understand what about your question is?
It is the signals/slots mechanism? Then you should read Qt documentationIt made no sense to me to paraphrase it.
If you have question after reading it, then I could try to help you to understand some details.
But explaining the hole concept here is too large for a post... -
@KroMignon said in How to share one signal for two slots.:
@jenya7 said in How to share one signal for two slots.:
I'd like to understand the whole concept.
My algorithm- Get a UDP message.
- Show a UDP message. (udp signal - main window slot)
Parse a UDP message. (udp signal - parser slot)
3.Put a parsed message in an array (parser signal - sensor class slot)
Everything connected in signal - slot paradigm?
Sorry but I don't understand what about your question is?
It is the signals/slots mechanism? Then you should read Qt documentationIt made no sense to me to paraphrase it.
If you have question after reading it, then I could try to help you to understand some details.
But explaining the hole concept here is too large for a post...I'm afraid in a complex application I can not pull off everything with a signal-slot mechanism.
It's an application that should run on RaspberryPi. Usually (in C compilers) I did it likevoid main(void) { //setup is here while (1) { //all stuff is here } }
So in Qt I'd do like this
int main(int argc, char *argv[]) { QThread main_thread; // = new QThread; worker *m_worker = new worker(); m_worker->moveToThread(&main_thread); QObject::connect(&main_thread, &QThread::started, m_worker, &worker::Process); } //in worker.cpp __attribute__ ((noreturn)) void worker::Process() { while (1) { ok = GetUdpMessage(); if (ok ) ParseUdpMessage); ProcessMessages(); RunScript); } }
Just guessing.
-
@jenya7 said in How to share one signal for two slots.:
I'm afraid in a complex application I can not pull off everything with a signal-slot mechanism.
It's an application that should run on RaspberryPi. Usually (in C compilers) I did it likeQt is an asynchronous C++ framework.
If you want to use Qt, you have to adapt your code to Qt.
Here are some good practices about Qt and threading https://www.kdab.com/the-eight-rules-of-multithreaded-qt/The under layered hardware is not that important. Embedded devices like RPi or power full PC , this only change the performances but not the programming style.
Signals/slots are there to made the classes as modular as possible.
With this mechanism, you can dynamically "route" information between all modules.
It also helps for multithreading, all required data copy are done when signal is "emitted".With
QObject
parent/child mechanism, you can simplify memory management, because on parent destruction, all children will be automatically destroyed.Often, there is no need to create an extra thread, because of asynchronous nature of Qt. Just ensure main thread is not locked by a forever loop so the event queue can run and process the signals/slots.
-
@jenya7 said in How to share one signal for two slots.:
how do I run periodical tasks? Not tied to any event, they should run constantly.
With
QTimer
==> https://doc.qt.io/qt-5/qtimer.html -
@KroMignon said in How to share one signal for two slots.:
@jenya7 said in How to share one signal for two slots.:
how do I run periodical tasks? Not tied to any event, they should run constantly.
With
QTimer
==> https://doc.qt.io/qt-5/qtimer.htmlBut where? Where do I create a scheduler? In main.cpp?
int main(int argc, char *argv[]) { QApplication a(argc, argv); MSGPARSER m_msgparser; MainWindow w; w.show(); QObject::connect(&w.wifi_udp, &MyUDP::GetUdpMessage, &m_msgparser, &MSGPARSER::GetUdpMessage); return a.exec(); }
-
@jenya7 said in How to share one signal for two slots.:
But where? Where do I create a scheduler? In main.cpp?
Where ever you want:
- in main
int main(int argc, char *argv[]) { QApplication a(argc, argv); QTimer tmr; QObject::connect(&tmr, &QTimer::timeout, []{) { // do your stuff here }); tmr.start(1000); // every second for example ... return a.exec(); }
- in a class
auto tmr = new QTimer(this);// use a parent to ensure timer is deleted when instance is destroyed QObject::connect(&tmr, &QTimer::timeout, this, &ThisClass:timerSlot); tmr->start(1000);
There are many options!