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

MainWindow GUI cannot call SLOT in worker thread UDP object



  • Hello,

    I am unable to emit() a signal from the MainWindow object to a worker thread that will send & receive UDP Data.
    The goal is to learn how to communicate from the GUI thread to the UDP thread.
    I do not understand why the SLOT is not working. I used the Mandlebrot example but in reverse, by communicating from GUI to thread. I tried QT4 & QT5 connect(signal, slot) functions without success. I get zero errors/warnings @ compile time

    Mandlebrot example:

    connect(&thread, SIGNAL(renderedImage(QImage,double)), this, SLOT(updatePixmap(QImage,double)));
    

    Mine in mainwindow.cpp:

    connect( this, SIGNAL(&MainWindow::runInitializeInthreadUDP), threadObj, SLOT(&MyUDP::Initialize), Qt::QueuedConnection);
    

    They only message I get from the "Application Output" is:

    QObject::connect: Parentheses expected, signal MainWindow::&MainWindow::runInitializeInthreadUDP in mainwindow.cpp:36
    

    Please see the attached code and if anyone is able to help, that would be very much appreciated.
    If more info is needed, please ask.

    Thank you,
    Keith

    //main.cpp

    #include "mainwindow.h"
    #include <QApplication>
    
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        qDebug()<<"From main GUI thread: "<<QThread::currentThreadId();
    
    
        //Create GUI, but it is not shown until GUI.show is called
        MainWindow GUI;
        //generate GUI screen when this main function is finished
        GUI.show();
    
        return a.exec();
    }
    
    

    //mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QtCore>
    
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0); //Class constructor
    
    private:
        Ui::MainWindow *ui;
    
    signals:
        void runInitializeInthreadUDP();
    
    private slots:
        void on_pushButton_clicked();
    };
    
    #endif // MAINWINDOW_H
    
    

    //mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QtCore>
    #include "myudp.h"
    #include "myThread.h"
    
    
    myThread* threadObj = new myThread();
    Worker* worker = new Worker();
    
    
    //MainWindow Class Constructor
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        //Create UDP object and startup worker thread
        //https://wiki.qt.io/QThreads_general_usage
        MyUDP udpObj;
        udpObj.moveToThread(threadObj);
        connect(worker, SIGNAL (&Worker::threadFinishedSignal), threadObj, SLOT (quit()));
        connect(worker, SIGNAL (&Worker::threadFinishedSignal), worker, SLOT (deleteLater()));
        connect(threadObj, SIGNAL (&Worker::threadFinishedSignal), threadObj, SLOT (deleteLater()));
        threadObj->start();
    
    
        //
        //
        //THIS NEXT PART DOES NOT WORK(Initialize() SLOT() function is never called)!!!!
        //
        //
        //initialize UDP ports
        //QT5 VERSION:
        connect( this, SIGNAL(&MainWindow::runInitializeInthreadUDP), threadObj, SLOT(&MyUDP::Initialize), Qt::QueuedConnection);
        //QT4 VERSION:
    //    connect( this, SIGNAL(runInitializeInthreadUDP()), threadObj, SLOT(Initialize()), Qt::QueuedConnection);
        emit runInitializeInthreadUDP();
    }
    
    
    //also does not work when pressing button on GUI (this _clicked function runs, but does not call SLOT &MyUDP::Initialize)
    void MainWindow::on_pushButton_clicked()
    {
        emit runInitializeInthreadUDP();
    }
    
    

    //mythread.h

    //#ifndef WORKERTHREAD_H
    //#define WORKERTHREAD_H
    
    #include <QtCore>
    
    
    //http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-1/
    class myThread : public QThread
    {
        Q_OBJECT
    
    private:
        void run()
        {
            qDebug()<<"From worker thread: "<<currentThreadId();
            connect(this, &QThread::finished, this, &QObject::deleteLater);
    
            exec();
        }
    };
    
    
    
    //https://wiki.qt.io/QThreads_general_usage
    class Worker : public QObject {
        Q_OBJECT
    
    signals:
        void threadFinishedSignal();
    };
    
    //#endif // WORKERTHREAD_H
    
    

    //myudp.h

    #ifndef UDP_H
    #define UDP_H
    
    //Base class QObject
    #include <QUdpSocket>
    #include <QtCore>
    
    
    class MyUDP : public QObject
    {
        Q_OBJECT
    
        public:
            MyUDP(); //Constructor for UDP Class Object
            ~MyUDP(); //Destructor for UDP Class Object
    
        private:
            QUdpSocket *socket;
    
        public slots:
            void UDPreadInputData();
            //Setup UDP port and connect port to fire function each time a UDP packet is received
            void Initialize();
    };
    
    
    #endif // UDP_H
    
    

    //myudp.cpp

    #include "myudp.h"
    #include <QtCore>
    
    
    //Settings for UDP addresses
    QHostAddress remoteAddress = QHostAddress("192.168.1.1");
    QHostAddress localAddress = QHostAddress("192.168.1.2");
    quint16 sendPort = 1234;
    quint16 receivePort = 5678;
    
    //UDP buffer that will contain the data received from microcontroller
    QByteArray Buffer;
    
    
    
    MyUDP::MyUDP() //Constructor for UDP Class Object
    {
    }
    MyUDP::~MyUDP() //Destructor for UDP Class Object
    {
    }
    
    
    
    void MyUDP::Initialize()
    {
        socket = new QUdpSocket(this);
    
        //We need to bind the UDP socket to an address and a port
    //    socket->bind(QHostAddress::LocalHost,receivePort);
        socket->bind(localAddress,receivePort);
        //Call the "UDPreadyRead" function each time the socket gets data on the defined UDP port
        connect(socket,SIGNAL(readyRead()),this,SLOT(UDPreadInputData()));
    
        qDebug()<<"UDP worker thread initialized";
    }
    
    
    
    //Read something
    void MyUDP::UDPreadInputData()
    {
        Buffer.resize(socket->pendingDatagramSize());
        int bufferSize = Buffer.size();
    
        //read sing UDP packet from hardware ethernet tranceiver on computer
        socket->readDatagram(Buffer.data(), bufferSize, &remoteAddress, &receivePort);
    
    //  http://lists.qt-project.org/pipermail/qt-interest-old/2009-June/008318.html
    //  Read float32 data types out with a QDataStream
        QDataStream ds( Buffer.mid( 0, bufferSize ) );
        //By default, a QDataStream is big endian and must be flipped depending on "processor architecture".
        ds.setByteOrder(QDataStream::LittleEndian);
        ds.setFloatingPointPrecision(QDataStream::SinglePrecision);
    
       //Throw out UDP Ethernet header and two bytes that are unused at beginning of packet (10 bytes)
       for(int i; i<5; i++)
       {
           qint16 temp; //each int16 is 2 bytes
           ds >> temp;
       }
    
       //Read the first two "start of sample bytes"
       qint16 HeaderByte1;
       ds >> HeaderByte1; //54321 start of sample int16
    }
    
    


  • Hi @kma005,

    I think this line:

    connect( this, SIGNAL(&MainWindow::runInitializeInthreadUDP), threadObj, SLOT(&MyUDP::Initialize), Qt::QueuedConnection);

    is mixing up the new and old slot syntaxes. Should probably be more like either:

    connect( this, SIGNAL(runInitializeInthreadUDP(type, ...)), threadObj, SLOT(Initialize(type, ...)), Qt::QueuedConnection);
    // or
    connect( this, &MainWindow::runInitializeInthreadUDP, threadObj, &MyUDP::Initialize, Qt::QueuedConnection);
    

    Note, the first version has argument types, and no & characters. And the second version has no SIGNAL nor SLOT macros.

    See https://wiki.qt.io/New_Signal_Slot_Syntax for further explanation.

    Cheers.



  • Paul,

    Please see in "mainwindow.cpp". I have already tried what you said for Qt4 compatibility.
    Both methods were already attempted, but without success.
    //QT5 VERSION:
    connect( this, SIGNAL(&MainWindow::runInitializeInthreadUDP), threadObj, SLOT(&MyUDP::Initialize), Qt::QueuedConnection);
    //QT4 VERSION:
    // connect( this, SIGNAL(runInitializeInthreadUDP()), threadObj, SLOT(Initialize()), Qt::QueuedConnection);
    emit runInitializeInthreadUDP();

    Thank you,
    Keith



  • Hi @kma005,

    Your Qt5 version is wrong, as I already described (should not have any SIGNAL nor SLOT macros).

    And both versions are trying to connect to an Initialize slot that does not exist on the receiver threadObj - it exists on udpObj only (if you corrected the Qt5 syntax, the compiler would have pointed that out).

    Also I suspect you'll need to allocate udpObj on the heap, eg:

    MyUDP * udpObj = new MyUDP;
    

    Otherwise it will be destroyed after the MainWindow constructor returns.

    Cheers.



  • Aside from the fact that class myThread does not have any slots, do you start an event loop within the thread? Without an event loop, the thread cannot receive signals.



  • THANK YOU PAUL COLBY!!!

    The issue was the new syntax does not use "SIGNAL() and SLOT()" macros.
    The "mainwindow.cpp" connect() function now does not have the "SIGNAL() and SLOT()" macros.

    Also the biggest issue was udpObj was destroyed when the mainwindow constructor finished.
    I made a "MyUDP *udpObj = new MyUDP();" declaration at the top of "mainwindow.cpp".
    next, "udpObj->moveToThread(threadObj);" is using an arrow since "udpObj" is now a pointer.

    Asperamanca, the thread event loop starts when "threadObj->start();" is called.
    the thread exec() function is called in "myThread.h"
    When "emit runInitializeInthreadUDP()" is called, "udpObj->Initialize()" will be called because the event loop in myThread is already running from the previous "threadObj->start();"

    THANK YOU PAUL COLBY!!!
    I will try to mark this solved.
    Keith

    Please see my updated "mainwindow.cpp" file:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QtCore>
    #include "myudp.h"
    #include "myThread.h"
    
    
    myThread *threadObj = new myThread();
    Worker *worker = new Worker();
    MyUDP *udpObj = new MyUDP();
    
    
    //MainWindow Class Constructor
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        //Create UDP object and startup worker thread
        //https://wiki.qt.io/QThreads_general_usage
    
        udpObj->moveToThread(threadObj);
        connect(worker, SIGNAL (&Worker::threadFinishedSignal), threadObj, SLOT (quit()));
        connect(worker, SIGNAL (&Worker::threadFinishedSignal), worker, SLOT (deleteLater()));
        connect(threadObj, SIGNAL (&Worker::threadFinishedSignal), threadObj, SLOT (deleteLater()));
        threadObj->start();
    
    
        //
        //
        //THIS NEXT PART DOES NOT WORK(Initialize() SLOT() function is never called)!!!!
        //
        //
        //initialize UDP ports
        //QT5 VERSION:
    //    connect( this, SIGNAL(&MainWindow::runInitializeInthreadUDP), threadObj, SLOT(&MyUDP::Initialize), Qt::QueuedConnection);
        connect( this, &MainWindow::runInitializeInthreadUDP, udpObj, &MyUDP::Initialize, Qt::QueuedConnection);
        //QT4 VERSION:
    //    connect( this, SIGNAL(runInitializeInthreadUDP()), threadObj, SLOT(Initialize()), Qt::QueuedConnection);
        emit runInitializeInthreadUDP();
    }
    
    
    //also does not work when pressing button on GUI (this _clicked function runs, but does not call SLOT &MyUDP::Initialize)
    void MainWindow::on_pushButton_clicked()
    {
        emit runInitializeInthreadUDP();
    }
    
    

  • Qt Champions 2019

    @kma005 said in MainWindow GUI cannot call SLOT in worker thread UDP object:

    connect() function now does not have the "SIGNAL() and SLOT()" macros

    This is not correct. SIGNAL/SLOT connect variant is still available (old syntax). Since Qt5 there is the new connect syntax without SIGNAL/SLOT. So, you can use both.
    Your problem was that you were mixing new and old connect syntax at the same time. You either use old or new syntax.

    Here you're mixing:

    connect(worker, SIGNAL (&Worker::threadFinishedSignal), threadObj, SLOT (quit()));
    

    It should be (old syntax):

    connect(worker, SIGNAL(threadFinishedSignal()), threadObj, SLOT (quit()));
    

    New syntax:

    connect(worker, &Worker::threadFinishedSignal, threadObj, &myThread::quit);
    


  • @jsulm said in MainWindow GUI cannot call SLOT in worker thread UDP object:

    @kma005 said in MainWindow GUI cannot call SLOT in worker thread UDP object:

    connect() function now does not have the "SIGNAL() and SLOT()" macros

    This is not correct. SIGNAL/SLOT connect variant is still available (old syntax).

    I think @kma005 was saying that his updated connect invocation in mainwindow.cpp is no longer using SIGNAL() and SLOT() macros, ie because he's removed them now. I don't think he was suggesting that the older syntax is no longer available.

    Cheers.


  • Qt Champions 2019

    @Paul-Colby OK, then I misunderstood the post


  • Moderators

    @Paul-Colby ,well no, @jsulm is correct.
    If the Please see my updated "mainwindow.cpp" file: is indeed the one @kma005 uses, than he's still using old and new syntax mixed in one statement:

    udpObj->moveToThread(threadObj);
        connect(worker, SIGNAL (&Worker::threadFinishedSignal), threadObj, SLOT (quit()));
        connect(worker, SIGNAL (&Worker::threadFinishedSignal), worker, SLOT (deleteLater()));
        connect(threadObj, SIGNAL (&Worker::threadFinishedSignal), threadObj, SLOT (deleteLater()));
        threadObj->start();
    
    
        //
        //
        //THIS NEXT PART DOES NOT WORK(Initialize() SLOT() function is never called)!!!!
        //
        //
        //initialize UDP ports
        //QT5 VERSION:
    //    connect( this, SIGNAL(&MainWindow::runInitializeInthreadUDP), threadObj, SLOT(&MyUDP::Initialize), Qt::QueuedConnection);
        connect( this, &MainWindow::runInitializeInthreadUDP, udpObj, &MyUDP::Initialize, Qt::QueuedConnection);
        //QT4 VERSION:
    //    connect( this, SIGNAL(runInitializeInthreadUDP()), threadObj, SLOT(Initialize()), Qt::QueuedConnection);
        emit runInitializeInthreadUDP();
    

    the only connect that will work from that code-example is:
    connect( this, &MainWindow::runInitializeInthreadUDP, udpObj, &MyUDP::Initialize, Qt::QueuedConnection);

    everything depending on the thread finished signal is ignored.



  • All,

    I assure you this line works in "mainwindow.cpp" and the "emit runInitializeInthreadUDP();" in mainwindow.cpp calls the function udpObj->Initialize().
    connect( this, &MainWindow::runInitializeInthreadUDP, udpObj, &MyUDP::Initialize, Qt::QueuedConnection);

    I simply omitted the SIGNAL() and SLOT() words and all is right with the world due to Paul Colby.
    I am using the QT5 syntax since the QT4 compiler did not catch the issue of threadObj->Initialize() was being called instead of udpObj->Initialize(). I had zero errors using the QT4 connect( this, SIGNAL(runInitializeInthreadUDP()), threadObj, SLOT(Initialize()), Qt::QueuedConnection); QT5 syntax for connect seems to catch those bad connection errors when compiling. When I used the QT5 syntax, it told me that udpObj should be used instead of threadObj in the connect() line.

    I apologize for the confusion.
    Thank you everyone. I just wanted to check back if people had additional questions and i am glad I did to clear this up.

    -Keith



  • @J.Hilk said in MainWindow GUI cannot call SLOT in worker thread UDP object:

    If the Please see my updated "mainwindow.cpp" file: is indeed the one @kma005 uses, than he's still using old and new syntax mixed in one statement:

    Yes, that is true - he's still using mixed syntaxes. However, the OP was only ever about the final connect - the one involving the MainWindow::runInitializeInthreadUDP signal, not the others. Its this last one that he's fixed, is no longer user mixed, and that his most recent comments were referring to.

    Indeed, he still has to go back and fix up the others too. He just wasn't claiming that the older syntax is not supported.

    Cheers.


Log in to reply