Search code examples
c++qtqtcoreqt-signalsqtimer

How to stop background loop after pushing button?


In my program, I open a window and run a big loop. I display progress in a QTextEdit. I added a cancel button to stop the big loop.

So in the window constructor I run a method that looks like,

void start()
{
    for (size_t i=0, i<10000000; ++i)
    {
        // do some computing
        QApplication::processEvents(); // Else clicking the stop button has no effect until the end of the loop
        if (m_stop) break; // member m_stop set to false at start.
    }
}

So, when I click the stop button, it runs the slot

void stopLoop()
{
    m_stop = true;
}

The problem with that method is that processEvents() slows the execution time a little too much.. But maybe it's inevitable ..

I wanted to try it with signals and slots, but I can't seem to think of how I could connect the pushed stop button with the loop.

Or, signals and slots or not, maybe someone has a better way of achieving this ?

EDIT

Following this thread advice, I now have a worker/thread scenario. So I have in a window constructor

Worker *worker;
QThread *thread ;
worker->moveToThread(thread); 
connect(thread, SIGNAL(started()), worker, SLOT(work()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start(); 

Which seems to work fine. But how could I introduce a QTimer now ?

Should I connect the QTimer to the thread's start() function

connect(timer, &QTimer::timeout, thread, &QThread::start);

Or, should I connect the thread to the QTimer's start() function ?

connect(thread, SIGNAL(started()), timer, &QTimer::start());

Or neither ... but then, how ?


Solution

  • use a QTimer

    void start()
    {
        this->timer = new QTimer(this);
        connect(timer, &QTimer::timeout, this, &MyObject::work);
        connect(stopbutton, &QButton::clicked, timer, &QTimer::stop);
        connect(stopbutton, &QButton::clicked, timer, &QTimer::deleteLater);
        connect(this, &MyObject::stopTimer, timer, &QTimer::deleteLater);
        connect(this, &MyObject::stopTimer, timer, &QTimer::stop);
        timer->setInterval(0);
        timer->setSingleShot(false);
        timer->start();
    
    }
    
    void work()
    {
       //do some work and return
    
       if (done)emit stopTimer();
    }