Problem With Qthread signal and slot



  • I'm new of Qt and I try to connect a signal event of a button with a method defined in my derived classes of QThread. So I have my Qthread class with the definition of run method and a slots

    @
    class Sensor : public QThread
    {
    Q_OBJECT
    private:
    void run() {//...cycle infinite// };

    private slots:
    void ExecSlot() {...};
    };
    @
    and in the main I have
    @
    QApplication a(argc, argv);

    Sensor *s1= new Sensor;
    QWidget *window = new QWidget;
    QPushButton *button = new QPushButton("b11 ");
    QPushButton *button1 = new QPushButton("b2 ");

    QHBoxLayout *layout = new QHBoxLayout;

    layout->addWidget(button);
    layout->addWidget(button1);
    window->setLayout(layout);
    window->show();

    s1->run();
    QObject::connect(button, SIGNAL(clicked()), eas1, SLOT(ExecSlot()));

    return a.exec();
    }@

    After compiling I have this error: QObject::connect: No such slot QThread::execslot().
    How can I Implement this functionality?
    Thanks

    Edit: please use the @ code tags around code sections; Andre



  • You have some type-o's in your code. I'm not sure if that was intended.

    @
    connect(button, SIGNAL(clicked()), s1, SLOT(ExecSLot()));
    @



  • thanks for your reply..

    The code that I have in my program is:

    @ QObject::connect(button, SIGNAL(clicked()), s1, SLOT(ExecSLot()));
    @
    but It doesn't work..

    It's a correct way to link a widget to a thread?



  • You seem to have at least three problems:

    • First, by the look of things, you don't have an event loop running in your Sensor thread. That is, you probably did not call exec() inside your run() implementation. That means that signal slot connections to slots in this object won't work. Please read the documentation (of a recent Qt version!) on how to use QThread properly. Subclassing and adding slots is almost never what you want to do.
    • Then, you're calling run() directly on your thread. You can't do that. Run is what gets called when the thread starts. That is, from inside the new thread. Call the start() method instead.
    • Then, you're declaring the slot private, and then trying to connect to it from the outside. That doesn't make a lot of sense.

    Don't take this the wrong way, but I don't think you're ready to use the tool "threading" just yet. Its a tool that has great power, and great potential to get you into all sorts of trouble.



  • Thanks Andre , He said what I wanna trying to say anyway

    QObject::connect: No such slot QThread::execslot().
    this error mean one of two reasons

    you don't have execslot() in your subclass

    Q_OBJECT macro isn't working and its happened only

    if you forget to implement it into your subclass
    or you forget to put your class in separate file with define lock outside main file

    I typed a simple code for you to able understand what you gonna do

    the follow is your Sensor class

    @
    #ifndef SENSOR_H
    #define SENSOR_H

    #include <QThread>
    #include <QDebug>

    class Sensor : public QObject
    {
    Q_OBJECT

    public:
    /*
    * QObject::moveToThread: Cannot move objects with a parent
    * so you gonna need to delete Sensor after you done
    * if you allocated in dynamic memory using malloc or new .. etc
    /
    Sensor() : QObject(0){
    /

    * Sub Classing QThread isn't a save way I can't explain the reasons right now
    * but you have to read about signals and slots
    */

        SensorThread  = new QThread;
        SensorThread->start();
    
        moveToThread(SensorThread);
    }
    
    ~Sensor(){
        SensorThread->deleteLater();
    }
    

    private:
    QThread *SensorThread;

    private slots: // private slots gonna make ExecSlot() calling only from QObject::connect
    void ExecSlot(){
    qDebug() << "ExecSlot Thread id " << QThread::currentThreadId();
    }
    };
    #endif // SENSOR_H
    @

    the follow is your main file code

    @
    #include "sensor.h"

    #include <QApplication>

    #include <QPushButton>
    #include <QHBoxLayout>

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);

    qDebug() << "main Thread id " << QThread::currentThreadId();
    
    
    QWidget window;
    
    QPushButton *button  = new QPushButton("b11 ");
    QPushButton *button1 = new QPushButton("b2 ");
    
    QHBoxLayout *layout = new QHBoxLayout;
    
    layout->addWidget(button);
    layout->addWidget(button1);
    
    
    window.setLayout(layout);
    
    window.show();
    
    Sensor  s1;
    
    QObject::connect(button, SIGNAL(clicked()), &s1, SLOT(ExecSlot()));
    
    return a.exec(&#41;;
    

    }
    @


  • Moderators

    Hi lalyperu,

    Please read through the "QThread documentation ":http://qt-project.org/doc/qt-5/QObject.html#thread-affinity carefully before trying to use QThreads.

    Also, read "QObject | Thread Affinity":http://qt-project.org/doc/qt-5/QObject.html#thread-affinity to understand how signals and slots work between threads.

    [quote]@class Sensor : public QThread@[/quote]A sensor is not a thread, and it doesn't manage a thread either. Therefore, a Sensor class should not inherit a QThread.



  • [quote author="seiko" date="1391636863"]
    I typed a simple code for you to able understand what you gonna do

    the follow is your Sensor class
    [/quote]
    No. Please don't follow this code.
    It is wrong to move the object owning a thread to that same thread, just like you should not move QThread to itself. Don't pull those kinds of tricks.

    Keep in mind that QThread is a class that manages a thread. It represents some kind of handle to that thread, and provides a starting point for it's execution path in its run method. It is not a thread, it is a QObject that lives, just like any other QObject, in the thread it was created it or was moved to. A thread is not an object. It is a context of execution of your code.



  • well Andre I shocked from your comment ...
    Who said "class Sensor" own SensorThread ..
    And It isn't kind of tricks it looks like the same way to
    Call "pthread_create" with a sync signals of event loop



  • [quote author="seiko" date="1391677546"]well Andre I shocked from your comment ...
    Who said "class Sensor" own SensorThread ..
    And It isn't kind of tricks it looks like the same way to
    Call "pthread_create" with a sync signals of event loop [/quote]

    You say that, in your code. Allow me to explain.
    In your first code path, you declare a class Sensor. Inside, you create a QThread object, who's sole pointer you store inside your Sensor class. That's ownership, is it not? Then, in line 26 you move your Sensor class instance to this new thread. So, you have moved the object that owns the QThread to the tread that manages that same QThread.



  • Well Andre I only stored pointer to be able to call deleteLater() at the end
    And that's not mean object ownership , that isn't "setParent"
    moveToThread gonna create a new "QThreadData" for sensor class
    without saving the pointer
    then its gonna send ThreadChange Event to prepare move
    then setThreadData_helper gonna call under mutex lock
    so no problem gonna happened

    At the end Andre maybe you are right , and you see something I don't understand yet on qt , I'm still new with qt and also using qt only on GUI painting instead of GTK

    Thank you again Andre for giving your time to help folks



  • I want to thank you for your collaboration.It's very helpful for me



  • I'm with Andre here.

    First off, if you read the "Notes" section of the "QThread":http://qt-project.org/doc/qt-4.8/qthread.html docs you will find two excellent examples of how threading should be done with Qt (written, in fact, by Andre ;o).

    Second, I've found that creating a class which manages both the thread and the worker as well as providing an interface to the rest of the application makes this far easier to understand and maintain. See the following very basic example:

    sensor.h
    @
    #ifndef SENSOR_H
    #define SENSOR_H

    #include <QObject>
    #include <QThread>
    #include <QDebug>

    class SensorWorker : public QObject{
    Q_OBJECT
    public:
    explicit SensorWorker(){}
    public slots:
    void run(){
    qDebug() << "Sensor Thread:" << QThread::currentThreadId();
    }
    };

    class Sensor : public QObject
    {
    Q_OBJECT
    public:
    explicit Sensor(QObject *parent = 0);
    ~Sensor();

    public slots:
    void start();
    void stop();

    private:
    QThread *thread;
    SensorWorker *worker;
    };

    #endif // SENSOR_H
    @

    sensor.cpp
    @
    #include "sensor.h"

    Sensor::Sensor(QObject *parent) :
    QObject(parent)
    {
    thread=new QThread(this);

    worker=new SensorWorker();
    connect(thread, SIGNAL(started()), worker, SLOT(run()));
    
    worker->moveToThread(thread);
    

    }

    Sensor::~Sensor(){
    stop();
    }

    void Sensor::start(){
    thread->start();
    }

    void Sensor::stop(){
    if(!thread->isRunning()) return;
    thread->quit();
    thread->wait();
    }
    @

    widget.h
    @
    #ifndef WIDGET_H
    #define WIDGET_H

    #include <QtGui/QWidget>
    #include "sensor.h"

    class Widget : public QWidget
    {
    Q_OBJECT

    public:
    Widget(QWidget *parent = 0);
    ~Widget();

    private:
    Sensor *sensor;
    };

    #endif // WIDGET_H
    @

    widget.cpp
    @
    #include <QVBoxLayout>
    #include <QPushButton>

    #include "widget.h"

    Widget::Widget(QWidget *parent)
    : QWidget(parent)
    {
    sensor=new Sensor(this);

    QVBoxLayout *l=new QVBoxLayout(this);
    
    QPushButton *start=new QPushButton("Start", this);
    connect(start, SIGNAL(clicked()), sensor, SLOT(start()));
    l->addWidget(start);
    
    QPushButton *stop=new QPushButton("Stop", this);
    connect(stop, SIGNAL(clicked()), sensor, SLOT(stop()));
    l->addWidget(stop);
    

    }

    Widget::~Widget(){}
    @

    main.cpp
    @
    #include <QtGui/QApplication>
    #include "widget.h"

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    Widget w;
    w.show();

    qDebug() << "Main Thread:" << QThread::currentThreadId();
    
    return a.exec&#40;&#41;;
    

    }
    @

    Hope this helps ;o)



  • You example was very clear and helpful for me.... But now I want to post another question...Only for test I implemented this code...

    testwork.h

    @
    #include <QtCore/qobject.h>
    #include <QtCore/qdebug.h>
    #include <QtCore/qthread.h>

    class testwork : public QObject
    {

    Q_OBJECT

    public:
    testwork();
    ~testwork();

    signals:

    void finished();
    

    public slots:
    void setVariable();
    void process();

    private:
    int buttonvar;

    };@

    testwork.cpp
    @
    #include "testwork.h"

    testwork::testwork()
    {
    buttonvar=0;
    }

    testwork::~testwork()
    {

    }

    void testwork::process()
    {
    qDebug() <<"Function Process "<<"Thread ID: "<< QThread::currentThreadId()<< endl;

    switch (buttonvar)
    {
    case 1:
    emit finished();
    };
    }

    void testwork::setVariable()
    {
    buttonvar =1;
    }@

    main.cpp
    @
    #include "testwork.h"

    int main(int argc, char *argv[]) {

    QApplication a(argc, argv);
    qDebug() << "Main Page init "<<"Thread Id:" << QThread::currentThreadId()<< endl;

    QWidget *window = new QWidget;
    QPushButton *setbutton = new QPushButton("set var ");
    QHBoxLayout *layout = new QHBoxLayout;

    layout->addWidget(setbutton);

    window->setLayout(layout);

     QThread* thread = new QThread;
     testwork* worker = new testwork();
    
     worker->moveToThread(thread);
    

    QObject::connect(thread, SIGNAL(started()), worker, SLOT(process()));
    QObject::connect(setbutton, SIGNAL(clicked()), worker, SLOT(setVariable()));
    QObject::connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
    QObject::connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
    QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

    thread->start();
    window->show();

    return a.exec();

    }@

    The QObject connections between the button setbutton and the slot setVariable doesn't work.. so if a clicked the button nothing happens.Is There something wrong?

    Thank you :)


  • Moderators

    Hi,

    How can you tell that testwork::setVariable() didn't work?

    You only called testwork::process() once, when the thread starts. It will not run again by itself when you call testwork::setVariable().



  • Hi,

    your question is right.. :) sorry there was my mistake in copy and paste the code.. I had inserted in setVariable slots a qDebug() <<"Set Variable called" only to see if the slot had been executed... but didn't happen...
    So I had thought there was a problem in a code but it wasn't...I had to recompile the code, run and the code worked well... I didn't understand where was the problem..but now works...

    Thanks for your time


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.