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

[SOLVED] Slots from a base class will not be called when subclassing it



  • Now, starting with Qt/qml I want to use my own threading class, based on
    QThread. I've read some articles, threads and blogs about QThread and learned
    that it is better not to subclass QThread directly but to implement a class
    that will instantiate a QThread object and use the moveToThread() method, what
    I finally did.

    So far it runs nicely, a thread may be created and started. But, as the following code is just the base implementation I want to subclass it for each thread I am going to use in my application. And then, the problem begins. In the ThreadBase class I have connected a slot (onThreadFinished()) to be called when the QThread finally has stopped working to delete the QThread instance.

    But that slot won't be called as soon as I have a derived implementation of the process() method.

    To be a bit more precise, here is the complete code:

    ThreadBase.h
    @
    #if(!defined(THREAD_BASE_H))
    #define THREAD_BASE_H

    #include "ThreadWorker.h"
    #include <QObject>

    class QThread;

    class ThreadBase : public QObject
    {
    Q_OBJECT

    public:
    ThreadBase(QString qstrObjectName = QString("USER_THREAD"));
    virtual ~ThreadBase();

    signals:
    void processingFinished();
    void error(QString qstrError);

    protected slots:
    virtual void process();
    virtual void onThreadFinished();
    virtual void onError(QString qstrError);

    protected:
    QThread* m_pThread;

    private:
    };

    #endif // THREAD_BASE_H
    @

    ThreadBase.cpp
    @

    #include <QThread>
    #include <QDebug>

    #include "ThreadBase.h"

    ThreadBase::ThreadBase(QString qstrObjectName)
    //: ThreadWorker()
    : QObject()
    {
    // create thred instance and pass over this worker instance
    m_pThread = new QThread;

    if(m_pThread)
    {
    m_pThread->setObjectName(qstrObjectName);
    this->moveToThread(m_pThread);

    connect(m_pThread,  SIGNAL(started()),            this,      SLOT(process()));
    connect(this,       SIGNAL(processingFinished()), m_pThread, SLOT(quit()));
    connect(this,       SIGNAL(processingFinished()), m_pThread, SLOT(deleteLater()));
    connect(m_pThread,  SIGNAL(finished()),           this,      SLOT(onThreadFinished()));
    
    m_pThread->start();
    

    }
    }

    ThreadBase::~ThreadBase()
    {
    delete m_pThread;
    }

    void ThreadBase::process()
    {
    qDebug("El Processo says: 'Base process() implementation... even if it's boring, nothing should ever happen here...'");
    emit processingFinished();
    }

    void ThreadBase::onThreadFinished()
    {
    qDebug() << "El Finito says: 'Thread " + m_pThread->objectName() + " has been shutted down... instance of ThreadBase may be destroyed now'";
    delete m_pThread;
    }

    void ThreadBase::onError(QString qstrError)
    {
    qDebug() << qstrError;
    }
    @

    That's for the base implementation. As said before, as long as I do not re-implement the process() method, the onThreadFinished() slot will be called as desired.

    Now for the derived class:

    MainLoop.h
    @
    #if(!defined(MAIN_LOOP__H))
    #define MAIN_LOOP__H

    #include "thread/ThreadBase.h"

    class MainLoop : public ThreadBase
    {
    Q_OBJECT

    public:
    MainLoop();
    virtual ~MainLoop();

    //re-implementation of process method to do some stuff...
    virtual void process();
    

    private:
    };

    #endif //MAIN_LOOP__H
    @

    MainLoop.cpp

    @
    #include "MainLoop.h"

    #include <QDebug>

    MainLoop::MainLoop()
    : ThreadBase("MAIN_LOOP")
    {
    }

    MainLoop::~MainLoop()
    {
    }

    void MainLoop::process()
    {
    qDebug("El Processo says: 'running Main Loop...'");
    }
    @

    When instatiating a MainLoop object, the processing will run perfectly, but the desired slot is never called.

    Now I hope someone here is able to enlighten me, what I have done wrong :)

    Best wishes,
    Coastcrawler

    ------------------------ SOLUTION: see last reply: http://qt-project.org/forums/viewreply/172919/


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    The problem is that in MainLoop, you don't declare process as a slot so it's a normal function.

    On a side note:

    @
    if(m_pThread)
    {@

    Is not really useful, if the allocation of m_pThread fails, your application has exhausted the available memory and will probably get killed by the system.



  • Hi SGaist,

    thanks for your welcome and your fast reply.

    I've just tried to as you wrote:

    @
    protected slots:
    virtual void process();
    @

    in the MainLoop.h to declare as a slot but it won't change the behaviour. The slot is still not called.

    And, what I found out was: the delete line in the ThreadBase::onThreadFinished() not only seems to be pointless as the Slot

    @
    connect(this, SIGNAL(processingFinished()), m_pThread, SLOT(deleteLater()));
    @

    will do the job of deleting the instance, it might also be dangerous as you never now if the thread is running, right? So, maybe the processingFinished() slot is just needless and the problem seems to be solved.

    But, in that case, how do I make sure all the other slots are called in the right manner?

    Best Regards,
    Coast


  • Lifetime Qt Champion

    Did you do a clean rebuild after you add the "protected slots" to MainLoop ?

    What do you mean by "right manner" ?



  • Well, with "the right manner" I meant how to check wether a slot is executed on the signals arrival or not.

    But anyway... I am just reading a blog ( http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-1 ) I guess, I just need much more knowledge and comprehension about Qt's signal/slot and threading system. Until then, we can stop at that stage of discussion.

    Thank you for your assistance. As soon as I found out about my problem, I will share my knowledge here :)


  • Lifetime Qt Champion

    You're welcome !

    You can also read the latest QThread "documentation":http://qt-project.org/doc/qt-5/qthread.html all cases are now described



  • The reason ThreadBase::onThreadFinished() isn't getting executed is because you override the method where the ThreadBase::processingFinished() signal is emitted. To remedy this, you could call ThreadBase::process() from MainLoop::process().

    The docs answer your question about deleteLater: http://qt-project.org/doc/qt-5/qobject.html#deleteLater



  • omfg... yes...

    Well... might be a beginners failure XD

    As I said, I need much more time until I really get used to the signal/slot mechanism.

    Thank you adolby and SGaist for your assistance :)


Log in to reply