Implement precise timer in Qt - c++

Since I need a more precise timer than the Qt one with its ~15ms resolution i tried to implement my own timer using QueryPerformanceCounter() from the windows api.
My first shot was to inherit from QObject and build a timer with an infinite loop that fires a signal every second. I tried to move this timer to its own thread with moveToThread() so that it would just update my main window every second and not block the whole thing. However the main window would never show up, removing the infinite loop -> main window shows up.
So I tried a singleshot approach, the basic idea is:
connect( highPerformanceTimer, SIGNAL(timer_tick()), this, SLOT(timeOutSlot()) );
connect( this, SIGNAL(graphics_updated()), highPerformanceTimer, SLOT(timer_start()));
So, timer ticks, ui (opengl) gets updated, at the end of the update a signal is generated to restart the timer.
Still my main window will not show up as long as i don't remove the restart of the timer from the end of the ui update code.
In the debugger I can see that the code seems to work like it should, it jumps from timer to ui and back. Without breakpoints it will result in a sudden segmentation fault.
I would be thankful for any hint where the problem could be or if there is a better way to implement this in Qt.
Edit: Some more code
highperformancetimer.h
#ifndef HIGHPERFORMANCETIMER_H
#define HIGHPERFORMANCETIMER_H
#include <QObject>
#include <windows.h>
class HighPerformanceTimer : public QObject
{
Q_OBJECT
public:
HighPerformanceTimer();
signals:
void timer_tick();
public slots:
void timer_start();
private:
// some variables
LARGE_INTEGER highPerformanceCounterValue, highPerformanceCounterFrequency, highPerformanceCounterValueOld;
int interval;
float value;
float last_tick_value;
};
#endif // HIGHPERFORMANCETIMER_H
highperformancetimer.cpp
#include "highperformancetimer.h"
#include "windows.h"
#include "QThread"
HighPerformanceTimer::HighPerformanceTimer()
{
QueryPerformanceFrequency(&highPerformanceCounterFrequency);
}
void HighPerformanceTimer::timer_start(){
float i = 0;
// just burn some time
while( i<1000000 ) i++;
emit HighPerformanceTimer::timer_tick();
}
Some Code from the main OpenGl Widget:
HighPerformanceTimer *highPerformanceTimer;
protected slots:
virtual void timeOutSlot();
NeHeChapter5( QWidget *parent=0, char *name=0 ) : NeHeWidget( 50, parent, name )
{
highPerformanceTimer = new HighPerformanceTimer();
connect( highPerformanceTimer, SIGNAL(timer_tick()), this, SLOT(timeOutSlot()) );
connect( this, SIGNAL(graphics_updated()), highPerformanceTimer, SLOT(timer_start()));
highPerformanceTimer->moveToThread(&timerThread);
highPerformanceTimer->timer_start();
}
void NeHeChapter5::timeOutSlot(){
timeOut();
}
void NeHeChapter5::timeOut()
{
updateGL();
}
void NeHeChapter5::paintGL()
{
//opengl code *snip*
emit graphics_updated();
}

Error is here:
NeHeChapter5( QWidget *parent=0, char *name=0 ) : NeHeWidget( 50, parent, name )
{
highPerformanceTimer = new HighPerformanceTimer();
connect( highPerformanceTimer, SIGNAL(timer_tick()), this, SLOT(timeOutSlot()) );
connect( this, SIGNAL(graphics_updated()), highPerformanceTimer, SLOT(timer_start()));
highPerformanceTimer->moveToThread(&timerThread);
highPerformanceTimer->timer_start();
}
You call timer_start(); and it's being called in caller thread, not in timerThread. Also you didn't even start your thread. Call timerThread.start() first. To invoke your timer_start() in thread you want you should call
QMetaObject::invokeMethod(highPerformanceTimer, "timer_start", Qt::QueuedConnection);
It will invoke timer_start in newly started thread, not in caller thread.
Also you don't need to call timer_tick with fully qualified name emit HighPerformanceTimer::timer_tick(); can be replaced with emit timer_tick();

Related

How to implement QProgressDialog?

I try to use a QProgressDialog to give the user some information on the progress of a long task, while allowing him to cancel this task.
Basically, I have a QDialog with a button Compute. By clicking on it, a time consuming method is called on a member of my QDialog's parent. This method takes a callback to tell the caller the progress of work.
The problem is that the progress dialog takes some time before appearing, and doesn't take into account immediately a click on its Cancel button.
It's clear that there is a glitch in my code, but I'm not accustomed with Qt, and I tried many things. I probably need a separate thread.
An extract of my code:
void MyDialog::callbackFunction(int value, void * objPtr) {
((QProgressDialog *)(objPtr))->setValue(value);
QCoreApplication::processEvents();
}
void MyDialog::on_mComputeBtn_clicked()
{
Compute();
}
void MyDialog::Compute()
{
QProgressDialog progressDialog("Optimization in progress...", "Cancel", 0, 100, this);
progressDialog.setMinimumDuration(500); // 500 ms
progressDialog.setWindowModality(Qt::WindowModal);
progressDialog.setValue(0);
connect(&progressDialog, SIGNAL(canceled()), this, SLOT(Cancel()));
QCoreApplication::processEvents();
parentMember->LongComputation(callbackFunction);
// probably useless
progressDialog.reset();
progressDialog.hide();
QCoreApplication::processEvents();
}
The dialog is not appearing immediately because you set a minimum duration of 500ms. Set it to 0 to make the dialog show immediately on progress change or call its show function manually.
In order to make the cancel button work, move your long computation to another thread ( e.g. use QThread or std::async ) and let your main event loop continue its execution.
Actually there are a lot of problems with your code but these two points should point you to the right direction. In my experience every manual call to processEvents is a big code smell.
What you do is trying to use modal paradigm of QProgressdialog, not letting main event pump to fire, also you set a 0.5 s timeout, minimal duration would ensure the pause. Maybe modeless variant is more appropriate for your case.
if process got discrete steps, you can do it without separate thread
class MyTask : public QObject
{
Q_OBJECT
public:
explicit MyTask(QObject *parent = 0);
signals:
public slots:
void perform();
void cancel();
private:
int steps;
QProgressDialog *pd;
QTimer *t;
};
...
void MyDialog::on_mComputeBtn_clicked()
{
myTask = new MyTask;
}
...
MyTask::MyTask(QObject *parent) :
QObject(parent), steps(0)
{
pd = new QProgressDialog("Task in progress.", "Cancel", 0, 100000);
connect(pd, SIGNAL(canceled()), this, SLOT(cancel()));
t = new QTimer(this);
connect(t, SIGNAL(timeout()), this, SLOT(perform()));
t->start(0);
}
void MyTask::perform()
{
pd->setValue(steps);
//... perform one percent of the operation
steps++;
if (steps > pd->maximum())
t->stop();
}
void MyTask::cancel()
{
t->stop();
//... cleanup
}
QThread example existed here: Qt 5 : update QProgressBar during QThread work via signal

Qt C++ - How to pass data from a worker thread to main thread?

I am trying to perform interthread communication in Qt (C++). I have a worker thread which does some calculations and I want the workerthread to return its results to the main thread when done. I therefor use a connect, I know thanks to debugging, that the signal is successfully being emit but that it is the slot that isn t being executed and I don t understand why.
The relevant pieces of code:
webcamClass::webcamClass(QObject *parent) : QObject(parent)
{
workerThread = new QThread(this);
workerClassObj = new workerClass();
//connect for image
connect(workerClassObj, SIGNAL(mySignal(QPixmap)), this, SLOT(mySlot(QPixmap)));
//connect(&workerClassObj, workerClass::mySignal(QPixmap), this, webcamClass::mySlot(QPixmap));
connect( workerThread, SIGNAL(started()), workerClassObj, SLOT(getImage()) );
workerClassObj->moveToThread(workerThread);
}
void webcamClass:: foo()
{
workerThread->start();
}
void workerClass::getImage()
{
qint64 successFailWrite;
QImage img;
QPixmap pixmap;
... do some stuff with pixmap...
qDebug()<<"going to emit result";
emit mySignal(pixmap);
qDebug()<<"emitted";
}
void webcamClass::mySlot(QPixmap p)
{qDebug()<<"this message should be displayed"; }
The corresponding header files:
class workerClass : public QObject
{
Q_OBJECT
private:
public:
explicit workerClass(QObject *parent = nullptr);
signals:
void mySignal(QPixmap);
};
webcamClass::webcamClass(QObject *parent) : QObject(parent)
{
Q_OBJECT
public:
explicit webcamClass(QObject *parent = nullptr);
public slots:
void mySlot(QPixmap p);
private:
QThread *workerThread;
workerClass *workerClassObj;
};
The code above just outputs:
going to emit result
emitted
but unfortunately doesn t output this message should be displayed.
webcamClass belongs to the parent thread, while workerClass belngs to -you guessed it- the worker thread.
Could someone explain how to setup my connect so that mySlot() gets triggered?
Thanks!
In the code you pasted in pastebin.com/UpPfrNEt you have a getVideoFrame method that uses while (1). If this method is called, it runs all the time and blocks the event loop from handling signals. You can solve it in many ways, I think the best practice will be to replace the while(1) with something else.
If possible, I highly encourage you to use the new Signal Slot syntax:
connect( SOURCEINSTANCE, &CLASS::SIGNAL, TARGETINSTANCE, &CLASS::SLOT );
In your case, that could be:
connect( workerClassObj, &workerClass::mySignal, this, &webcamClass::mySlot );
Specificallyfor your case, if you want to pass Signals and Slots between threads, you have to be careful. First, check the connection type for the connect call, its acutally the last parameter.
connect( workerClassObj, &workerClass::mySignal, this, &webcamClass::mySlot, Qt::QueuedConnection );
For a detailed explanation look here:
http://doc.qt.io/qt-5/signalsandslots.html
If you want to pass custom types, you have to declare them as metatypes first.
Add e.G. this in your constructor:
qRegisterMetaType("MyDataType");
Please make sure, that your custom datatype has a default constructor and be aware that afaik, references cannot be passed across threads.

Repaint splash screen from thread / disable assertion

Problem
I want to use a QTimer to update a derived QSplashScreen that draws a progress bar (using paint commands, not a widget) to estimate when the program will start running.
By necessity, this happens prior to the exec call of the QCoreApplication. I've gotten this to work (in release mode only) on both X11 and Windows, by putting a timer in a second thread, and calling a function in the splash screen which updates the progress and repaints the widget. However, this doesn't work in debug mode as it produces the following error:
"ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread."
I'm not really worried about this assertion as the code doesn't crash in release and it's just a splash screen, however I need to be able to run the program in debug so I'd like to either a) refactor the code so it doesn't trigger the assertion, or b) dissable this particular assertion.
Tried:
Using update() instead of repaint(). This doesn't cause an assertion, but it also doesn't repaint because the main thread is too busy loading in the shared libraries, etc, and the timer events don't get processed until I'm ready to call finish on the splash screen.
starting QTimer in main loop. Same result as above.
Using a QT::QueuedConnection. Same result.
Main
#include <QApplication>
#include <QtGui>
#include <QTimer>
#include <QThread>
#include "mySplashScreen.h"
#include "myMainWindow.h" // contains a configure function which takes a
// LONG time to load.
int main( int argc, char* argv[] )
{
// estimate the load time
int previousLoadTime_ms = 10000;
QApplication a(argc, argv);
MySplashScreen* splash = new MySplashScreen(QPixmap(":/splashScreen"));
// progress timer. Has to be in a different thread since the
// qApplication isn't started.
QThread* timerThread = new QThread;
QTimer* timer = new QTimer(0); // _not_ this!
timer->setInterval(previousLoadTime_ms / 100.0);
timer->moveToThread(timerThread);
QObject::connect(timer, &QTimer::timeout, [&]
{
qApp->processEvents(); splash->incrementProgress(1);
});
QObject::connect(timerThread, SIGNAL(started()), timer, SLOT(start()));
timerThread->start();
splash->show();
a.processEvents();
myMainWindow w;
QTimer::singleShot(0, [&]
{
// This will be called as soon as the exec() loop starts.
w.configure(); // this is a really slow initialization function
w.show();
splash->finish(&w);
timerThread->quit();
});
return a.exec();
}
Splash Screen
#include <QSplashScreen>
class MySplashScreen : public QSplashScreen
{
Q_OBJECT
public:
MySplashScreen(const QPixmap& pixmap = QPixmap(), Qt::WindowFlags f = 0)
: QSplashScreen(pixmap, f)
{
m_pixmap = pixmap;
}
virtual void drawContents(QPainter *painter) override
{
QSplashScreen::drawContents(painter);
// draw progress bar
}
public slots:
virtual void incrementProgress(int percentage)
{
m_progress += percentage;
repaint();
}
protected:
int m_progress = 0;
private:
QPixmap m_pixmap;
};
MyMainWindow
#include <QMainWindow>
class myMainWindow : public QMainWindow
{
public:
void configure()
{
// Create and configure a bunch of widgets.
// This takes a long time.
}
}
The problems are because the design is backwards. The GUI thread should not be doing any loading. The general approach to GUI threads is: do no work in the GUI thread. You should spawn a worker thread to load what you need loaded. It can post events (or invoke slots using a queued connection) to the GUI thread and its splash screen.
Of course, the worker thread should not create any GUI objects - it can't instantiate anything deriving from QWidget. It can, though, instantiate other things, so if you need any expensive-to-obtain data, prepare it in the worker thread, and then cheaply build a QWidget in the GUI thread once that data is available.
If your delays are due to library loading, then do load all the libraries in a worker thread, explicitly, and ensure that all of their pages are resident in memory - for example by reading the entire .DLL after you're loaded it as a library.
The MyMainWindow::configure() could be called in a worker thread, as long as it doesn't invoke any QWidget methods nor constructors. It can do GUI work, just not visible on screen. For example, you can load QImage instances from disk, or do painting on QImages.
This answer provides several approaches to executing a functor in a different thread, GCD-style.
If you are constructing widgets that are expensive to construct, or construct many of them, it's possible to make sure that the event loop can run between the instantiation of each widget. For example:
class MainWindow : public QMainWindow {
Q_OBJECT
QTimer m_configureTimer;
int m_configureState = 0;
Q_SLOT void configure() {
switch (m_configureState ++) {
case 0:
// instantiate one widget from library A
break;
case 1:
// instantiate one widget from library B
...
break;
case 2:
// instantiate more widgets from A and B
...
break;
default:
m_configureTimer.stop();
break;
}
}
public:
MainWindow(QWidget * parent = 0) : QMainWindow(parent) {
connect(&m_configureTimer, SIGNAL(timeout()), SLOT(configure()));
m_configureTimer.start(0);
//...
}
};

QMutex in slots

Suppose to have the following QT code (QT 5.3.1):
void SenderClass::runSignal()
{
emit mySignal();
}
void ReceiverClass::ReceiverClass()
{
...
connect (senderClassRef, SIGNAL(mySignal()), this, SLOT(mySlot()) );
}
void ReceiverClass::mySlot()
{
//Long operation executions
Sleep(1000);
qDebug() << "1";
Sleep(1000);
qDebug() << "2";
Sleep(1000);
qDebug() << "3";
}
Calling runSignal() consecutively it happens that console displays something like:
1 2 1 3 2 3
The 2 classes live in the same thread.
Do I have to use a QMutexLocker in slots?? Or is there an another way to have an ordered output like:
1 2 3 1 2 3
so preventing a call of mySlot() function if there's still one executing.
UPDATE
Here follow a real code snippet.
The sender:
//Sender.h
#include <QtWidgets/QWidget>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QTextBrowser>
class Receiver;
class Sender : public QWidget
{
Q_OBJECT
public:
Sender(QWidget *parent = 0);
QPushButton *pushButton;
QTextBrowser *textBrowser;
Receiver* receiver;
signals:
void buttonClickedSignal();
public slots:
void ButtonClickedSlot();
};
//Sender.cpp
#include "Sender.h"
#include "Receiver.h"
#include <QObject>
Sender::Sender(QWidget *parent)
: QWidget(parent)
{
pushButton = new QPushButton(this);
pushButton->setObjectName(QStringLiteral("pushButton"));
pushButton->setGeometry(QRect(150, 30, 75, 23));
pushButton->setText("Button");
textBrowser = new QTextBrowser(this);
textBrowser->setObjectName(QStringLiteral("textBrowser"));
textBrowser->setGeometry(QRect(50, 90, 256, 192));
receiver = new Receiver(this);
QObject::connect(pushButton, SIGNAL(clicked()), this, SLOT(ButtonClickedSlot()));
}
void Sender::ButtonClickedSlot()
{
emit buttonClickedSignal();
}
The receiver:
//Receiver.h
#include "Sender.h"
class Receiver : QObject
{
Q_OBJECT
public:
Receiver(Sender *sender);
Sender *m_sender;
public slots:
void ReceiverSlot();
};
//Receiver.cpp
#include "Receiver.h"
#include <QObject>
#include <QThread>
#include <QApplication>
Receiver::Receiver(Sender *sender)
{
m_sender = sender;
QObject::connect(m_sender, SIGNAL(buttonClickedSignal()), this, SLOT(ReceiverSlot()), Qt::QueuedConnection);
}
void Receiver::ReceiverSlot()
{
m_sender->textBrowser->append("1");
QThread::msleep(100);
qApp->processEvents();
m_sender->textBrowser->append("2");
QThread::msleep(100);
qApp->processEvents();
m_sender->textBrowser->append("3");
QThread::msleep(100);
qApp->processEvents();
m_sender->textBrowser->append("4");
QThread::msleep(100);
qApp->processEvents();
}
Clicking the button quickly results in not consecutive numbers in QTextBrowser, even if a QueuedConnection is set.
UPDATE 2
What I would like to achieve is a queued access to the ReceiverSlot. The user can click the button with any freedom (when he wants and at any speed). The ReceiverSlot cannot miss any event. I need some sort of event queuing so that (long) operations in the ReceiverSlot are always executed, maybe delayed, but executed.
Get rid of QApplication::processEvents and move the long operation that freezes your GUI to a new thread. You can use for example a worker object that you move to a new thread. There is a good example of this in the docs.
You should also read this to learn more about threads and events in Qt. There is an exact same situation as yours explained in the forcing event dispatching part:
Be very careful when reentering the event loop “by other paths”: it can lead to unwanted recursions! Let’s go back to the Button example. If we call QCoreApplication::processEvents() inside the doWork() slot, and the user clicks again on the button, the doWork() slot will be invoked again:
main(int, char **) QApplication::exec()
[…]
QWidget::event(QEvent *)
Button::mousePressEvent(QMouseEvent *)
Button::clicked()
[…]
Worker::doWork() // first, inner invocation
QCoreApplication::processEvents() // we manually dispatch events and…
[…]
QWidget::event(QEvent * ) // another mouse click is sent to the
Button…
Button::mousePressEvent(QMouseEvent *)
Button::clicked() // which emits clicked() again…
[…]
Worker::doWork() // DANG! we’ve recursed into our slot.
In general you want to avoid QApplication::processEvents and creating local event loops. If you have these in your code, then you should redesign it so you won't have to use these.
Worker object examlpe from the docs:
class Worker : public QObject
{
Q_OBJECT
QThread workerThread;
public slots:
void doWork(const QString &parameter) {
// ...
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(this, SIGNAL(operate(QString)), worker, SLOT(doWork(QString)));
connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
To turn my comments into a proper answer:
If, when in your slot you call qApp->processEvents() there is a mouse press event waiting to be delivered to the button, it will be delivered, and the clicked() signal will be emitted again, and thus your slot will be called again.
A QMutex will not help, because there is no threading involved. Adding one would most likely result in your program deadlocking.
Using Qt::QueuedConnection doesn't help, because this posts an event to the queue which, when processed, will result in your slot being invoked. So it just, at best, delays it until the next time you call qApp->processEvents().
In the context of your example, my suggestion would be to get rid of the queued connection, and instead disable the button while the slot is working. This will prevent the clicked() signal being emitted again, and also show the user that they shouldn't be trying to click on the button at this time.
If for whatever reason you don't want to do that, you could add a flag to your receiver class to prevent recursive calls. Something like this will do the trick, although it's not very pretty:
void Receiver::ReceiverSlot()
{
if( m_inSlot )
return;
m_inSlot = true;
// do work
m_inSlot = false;
}

how to add a 1 second delay using Qtimer

I currently have a method which is as follows
void SomeMethod(int a)
{
//Delay for one sec.
timer->start(1000);
//After one sec
SomeOtherFunction(a);
}
This method is actually a slot that is attached to a signal. I would like to add a delay of one sec using Qtimer.However I am not sure on how to accomplish this. Since the timer triggers a signal when its finished and the signal would need to be attached to another method that does not take in any parameters. Any suggestion on how I could accomplish this task.?
Update :
The signal will be called multiple times in a second and the delay will be for a second. My issue here is passing a parameter to the slot attached to timeout() signal of a timer.
My last approach would be to store the value in a memeber variable of a class and then use a mutex to protect it from being changed while the variable is being used .however I am looking for simpler methods here.
Actually, there is a much more elegant solution to your question that doesn't require member variables or queues. With Qt 5.4 and C++11 you can run a Lambda expression right from the QTimer::singleShot(..) method! If you are using Qt 5.0 - 5.3 you can use the connect method to connect the QTimer's timeout signal to a Lambda expression that will call the method that needs to be delayed with the appropriate parameter.
Edit: With the Qt 5.4 release it's just one line of code!
Qt 5.4 (and later)
void MyClass::SomeMethod(int a) {
QTimer::singleShot(1000, []() { SomeOtherFunction(a); } );
}
Qt 5.0 - 5.3
void MyClass::SomeMethod(int a) {
QTimer *timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [=]() {
SomeOtherFunction(a);
timer->deleteLater();
} );
timer->start(1000);
}
I'm a bit confused by the way you phrase your question, but if you're asking how to get the timer's timeout() signal to call a function with a parameter, then you can create a separate slot to receive the timeout and then call the function you want. Something like this: -
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass(QObject *parent);
public slots:
void TimerHandlerFunction();
void SomeMethod(int a);
private:
int m_a;
QTimer m_timer;
};
Implementation: -
MyClass::MyClass(QObject *parent) : QObject(parent)
{
// Connect the timer's timeout to our TimerHandlerFunction()
connect(&m_timer, SIGNAL(timeout()), this, SLOT(TimerHandlerFunction()));
}
void MyClass::SomeMethod(int a)
{
m_a = a; // Store the value to pass later
m_timer.setSingleShot(true); // If you only want it to fire once
m_timer.start(1000);
}
void MyClass::TimerHandlerFunction()
{
SomeOtherFunction(m_a);
}
Note that the QObject class actually has a timer that you can use by calling startTimer(), so you don't actually need to use a separate QTimer object here. It is included here to try to keep the example code close to the question.
If you are calling SomeMethod multiple times per second and the delay is always constant, you could put the parameter a to a QQueue and create a single shot timer for calling SomeOtherFunction, which gets the parameter from the QQueue.
void SomeClass::SomeMethod(int a)
{
queue.enqueue(a);
QTimer::singleShot(1000, this, SLOT(SomeOtherFunction()));
}
void SomeClass::SomeOtherFunction()
{
int a = queue.dequeue();
// do something with a
}
That doesn't work because QTimer::start is not blocking.
You should start the timer with QTimer::singleShot and connect it to a slot which will get executed after the QTimer times out.