PDA

View Full Version : Why isn't QTimer asynchronous?



Hossein
10th October 2015, 21:28
I tried to use a simple `QTimer` object on my window widget so that I can calculate the elapsed time a method takes to complete.
But to my astonishment! the timer was blocked until the method completes execution! i.e when the method in question ends, the timer starts ticking!!
Here is a sample code to demonstrate what I wrote:



#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

private slots:
void on_btnTest_clicked();
void OnTimerTick();

private:
Ui::MainWindow *ui;
ulong seconds;
};

#endif // MAINWINDOW_H



#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv/cv.h"
#include <QTimer>
#include <QtCore>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}

MainWindow::~MainWindow()
{
delete ui;
}


void MainWindow::on_btnTest_clicked()
{
QTimer * timer = new QTimer(0);
seconds =0;
connect(timer,SIGNAL(timeout()),this,SLOT(OnTimerT ick()));

timer->setInterval(100);
timer->start();

QThread::sleep(5);//simulating a method which takes 5 seconds to complete

//timer->stop();

}

void MainWindow::OnTimerTick()
{
ui->lblElapsedTime->setText(QString::number(++seconds));
}




How can I get the asynchronous behavior, something like what we have in C#? where the Timer runs its own thread of execution?

ars
10th October 2015, 21:53
For measuring the time a function call takes use QTime::elapsed() method instead of a QTimer object. Example:

QTime t;
t.start();
myFunction(...);
std::cout << "myFunction(): " << t.elapsed() << "ms"
See also http://doc.qt.io/qt-5.4/qtime.html#start.
Best regards
ars

ChrisW67
10th October 2015, 22:10
If you want the elapsed time display to update during the long running process then that process must relinquish control to the Qt event loop periodically (QApplication::processEvents()) or run in a separate thread, allowing the main thread to handle the GUI updates. How you put the long running process in a separate thread depends on the process a bit: see:
http://doc.qt.io/qt-5/qtconcurrentrun.html
http://doc.qt.io/qt-5/qthread.html
And also the venerable but generally useful
https://doc.qt.io/archives/qq/qq27-responsive-guis.html

Hossein
11th October 2015, 11:17
thank you guys ,I appreciate it

If you want the elapsed time display to update during the long running process then that process must relinquish control to the Qt event loop periodically (QApplication::processEvents()) or run in a separate thread, allowing the main thread to handle the GUI updates. How you put the long running process in a separate thread depends on the process a bit: see:
http://doc.qt.io/qt-5/qtconcurrentrun.html
http://doc.qt.io/qt-5/qthread.html
And also the venerable but generally useful
https://doc.qt.io/archives/qq/qq27-responsive-guis.html

Yes thats exactly the case, Thanks I 'll have alook at it .
By the way Is it not more logical to make QTimer run its own thread of execution in essence? since it will be literally emitting every x time, and most of the time this will be in conjunction with other stuff happening in parallel to it.
In C# this concept is very well implemented and makes sense if you look at it.

anda_skoa
11th October 2015, 13:14
By the way Is it not more logical to make QTimer run its own thread of execution in essence?

That would just make things unnecessarily complex for the common use case where you just want to trigger a function every X milliseconds.
Since it is easy enough to move a timer to a secondary thread, there is no need to make the common case more complex by forcing multithreading into the application.

Your example demonstrates actually very well that multithreading is something one has to explicitly thing about.

The primary objective should always be to keep the UI from becoming unresponsive. Blocking its thread with a long running operation is very bad for that goal.
Instead of looking for a way to keep the timer responsive, you should be looking at keeping the UI responsive.

The part that should run in the secondary thread is the part that blocks, the code that takes long to execute.


Cheers,
_

Hossein
11th October 2015, 20:02
Thanks, thats pretty reasonable,