Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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 do

    extern  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:

    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.



  • Where is an instance of your parser class created and how are you trying to connect to it?



  • @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 class MainWindow.
    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);
    }
    


  • Where is an instance of your parser class created?



  • @ChrisW67 said in How to share one signal for two slots.:

    Where is an instance of your parser class created?

    main.cpp

    int main(int argc, char *argv[])
    {
        MSGPARSER m_msgparser;
    
        MainWindow w;
        w.show();
    }
    


  • @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 that MyUDP wifi_udp; does NOT exist ==> MyUDP wifi_udp != MainWindow::wifi_udp

    This 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);
    
    }
    


  • Thank you.
    QObject::connect(&w.wifi_udp, &MyUDP::GetUdpMessage, &m_msgparser, &MSGPARSER::GetUdpMessage);
    works good.



  • @jenya7 said in How to share one signal for two slots.:

    Thank you.
    QObject::connect(&w.wifi_udp, &MyUDP::GetUdpMessage, &m_msgparser, &MSGPARSER::GetUdpMessage);
    works good.

    I hope you have understand why and what you have do wrong.



  • I'd like to understand the whole concept.
    My algorithm

    1. Get a UDP message.
    2. 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?



  • @jenya7 said in How to share one signal for two slots.:

    I'd like to understand the whole concept.
    My algorithm

    1. Get a UDP message.
    2. 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 documentation

    It 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

    1. Get a UDP message.
    2. 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 documentation

    It 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 like

    void 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 like

    Qt 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.



  • @KroMignon
    Thank you. One more question - how do I run periodical tasks? Not tied to any event, they should run constantly.



  • @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.html

    But 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!



  • Thank you.


Log in to reply