how to add a 1 second delay using Qtimer - c++

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.

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.

QtConcurrent: Inform another function that result is ready

I'm new to the C++ and QT world. I need to do some modifications on an existing console application.
I have the following problem: I'm running some functions (which take some time) concurrently and show a wait indicator during this time. The setup looks like this:
QFuture<void> doStuff = QtConcurrent::run(longCalc, param1, param2);
showWaitIndicator(&doStuff);
// ....
void showWaitIndicator(QFuture<void> *future)
{
while (future->isRunning()) {
// Show some nice indicator and so on.
}
}
This setup works just fine, but now I want to run some other tasks concurrently which have another return type and I need to access the result. Instead of QFuture<void>these are mostly QFuture<double>, QFuture<int>, etc: QFuture<double> doStuff = QtConcurrent::run(doubleCalc);
I also want to display my nice wait indicator, but the different return types mean I can't use my current showWaitIndicator() function.
Is there a good way to improve this "setup"? I'm new to C++, so I'm pretty sure there must be a way. My first idea was function overloading but this didn't work because the parameters have the same type (QFuture).
TL;DR: I need to inform my showWaitIndicator() function that QFuture finished.
You can emit a custom signal from the function that runs concurrently, or use a QFutureWatcher as a source of such signal.
E.g. when longCalc is in the same class:
MyClass::MyClass() {
Q_OBJECT
Q_SIGNAL void longCalcDone();
connect(this, &MyClass::longCalcDone, this, [this]{
...
});
}
void MyClass::longCalc(int arg1, int arg2) {
...
emit MyClass::longCalcDone();
}
E.g. when longCalc is a free function or is in another class:
void longCalc(int, int);
MyClass::MyClass() {
Q_OBJECT
Q_SIGNAL void longCalcDone();
connect(this, &MyClass::longCalcDone, this, [this]{
...
});
void doStuff() {
QtConcurrent::run([=]{
longCalc(param1, param2);
emit longCalcDone();
});
}
}
E.g. with a future watcher instead:
class MyClass : public QObject {
QFutureWatcher watcher;
MyClass() {
connect(&watcher, &QFutureWatcher::finished, this, [this]{
...
});
}
void doStuff() {
auto future = QtConcurrent::run(longCalc, this, param1, param2);
watcher.setFuture(&future);
}
};
The while (future->isRunning()) synchronous code is an anti-pattern. Presumably you invoke QCoreApplication::processEvents within that loop. The problem is - the world is not like that, you can't take the locus of control away from the event loop and pretend that the world revolves around you. Instead, invert the control flow and have your code (a slot, a method or a functor) invoked when the future finishes.
See also this question.

crash. QObject::connect in a constructor of a static object instance

I'm trying to find out why my app crashes for the whole day. A picture worth thousands of words, so take a look at this code. Header:
class SandboxedAppStat : public QObject
{
Q_OBJECT
private slots:
void pidsTimerTimeout();
public:
QTimer m_PidsTimer;
SandboxedAppStat(QObject *parent = NULL);
};
class SandboxedApp : public QObject
{
Q_OBJECT
private:
static SandboxedAppStat SandboxedAppStat1;
};
Implementation:
void SandboxedAppStat::pidsTimerTimeout()
{
qDebug() << "whatever";
}
SandboxedAppStat::SandboxedAppStat(QObject *parent)
: QObject(parent)
{
bool b = QObject::connect(&m_PidsTimer, SIGNAL(timeout()),
this, SLOT(pidsTimerTimeout()));
m_PidsTimer.start(500);
}
SandboxedAppStat SandboxedApp::SandboxedAppStat1;
Actually what I'm trying to do, is to simulate static constructor behavior in C++. I want
QObject::connect(&m_PidsTimer, SIGNAL(timeout()),
this, SLOT(pidsTimerTimeout()));
m_PidsTimer.start(500);
to be called as soon as the static member SandboxedAppStat1 initializes. That's why the code shown above is in the constructor of SandboxedAppStat.
However, my problem is that when I run the program, it crashes as soon as it reaches the line connect(&m_PidsTimer, SIGNAL(timeout()), this, SLOT(pidsTimerTimeout()));
with error code c0000005 (access violation I guess).
here's the screenshot http://dl.dropbox.com/u/3055964/Untitled.gif
If I declare SandboxedAppStat as a non static variable, then there is no crash and no errors. everything works fine.
First I thought that crash reason could be the fact that, static members are initialized too early for QObject::connect to be able to be called, that's why I updated SandboxedAppStat constructor with the following code:
auto *t = this;
QtConcurrent::run([&] () {
Sleep(3000);
bool b = QObject::connect(&(t->m_PidsTimer),
SIGNAL(timeout()), t, SLOT(pidsTimerTimeout()));
t->m_PidsTimer.start(500);
});
As you can see, QObject::connect executes after 3 seconds when static SanboxedAppStat is initialized, but this didn't help either, the program crashes after 3 seconds.
I'm really confused, I don't understand what can be the cause of this problem. Can't we use signal/slots in a static object instances?
I'm using Qt 4.8.0 with MSVC 2010. Thanks
UPDATE
Here's a simple project, consisting of only one header and one source file (as HostileFork suggested) to reproduce the crash. http://dl.dropbox.com/u/3055964/untitled1.zip
Are you looking for periodic calling of your pidsTimerTimeout slot or just once during construction?
If you're looking to just receive a signal once your class has been constructed try using QTimer::singleShot or QMetaObject::invokeMethod if you don't require continuous time outs. Like all signals the single shot will only be acted upon once the window system's event queue have been processed which can have a small delay on the execution of your slot.
MyClass::MyClass()
{
// Using a zero singles shot.
QTimer::singleShot( 0, this, SLOT( initialized() ) );
// or using invoke method.
QMetaObject::invokeMethod( this, "initialized", Qt::QueuedConnection );
}
Pretty sure we use this code in the office and we have success with static objects.

QT threads :Getting QObject::startTimer: timers cannot be started from another thread warning

I follow the examples from the Qt SDK, starting timer in the QThread Subclass
but I keep getting the warning and the thread never starts the timer.
Here is the code:
NotificationThread::NotificationThread(QObject *parent)
:QThread(parent),
m_timerInterval(0)
{
moveToThread(this);
}
NotificationThread::~NotificationThread()
{
;
}
void NotificationThread::fire()
{
WRITELOG("A::fire called -- currentThread:" + QString::number((int)currentThread()->currentThreadId()));
QVector<StringPer>* batchVectorResult = new QVector<StringPer>();
emit UpdateGroupNotifications(batchVectorResult);
}
void NotificationThread::run()
{
connect(&m_NotificationTimer, SIGNAL(timeout()),
this,SLOT(fire(),Qt::DirectConnection));
WRITELOG("A::run() worker thread -- currentThread:" + QString::number((int)currentThread()->currentThreadId()));
//SetNotificationTimerFromConf();
QVariant val(ConfigSettings::getInstance()->ReadFromSettingsReturnVariant(SETTINGS_KEY_NOTIFICATIONTHREAD));
int interval = val.toInt();
m_NotificationTimer.setInterval(interval);
m_NotificationTimer.start();
QThread::exec();
}
void NotificationThread::SetNotificationTimerFromConf()
{
QVariant val(ConfigSettings::getInstance()->ReadFromSettingsReturnVariant(SETTINGS_KEY_NOTIFICATIONTHREAD));
int interval = val.toInt();
m_NotificationTimer.setInterval(interval);
}
void NotificationThread::UpdateNotificationTimerRT(int timerInterval)
{
m_NotificationTimer.setInterval(m_timerInterval);
}
void NotificationThread::Execute(const QStringList batchReqList)
{
QVector<QString>* batchVectorResult = new QVector<QString>();
start();
}
I start the Thread from the main GUI with Execute( ).
The problem is that you create the timer implicitly by the main thread when you create your thread object. This is because your timer is a member of your thread class.
When you try to start the timer, you do in a different thread (in run()), not in the thread where the timer was created, which gives you the warning.
You need to create the timer in the thread where you want to run it:. Change the declaration of m_notificationTimer in your NotificcationThread class from
QTimer m_NotificationTimer;
to
QTimer* m_NotificationTimer;
and create the timer in run() with
m_NotificationTimer = new QTimer(this);
m_NotificationTimer->setInterval(interval);
m_NotificationTimer->start();
If you add the line
m_NotificationTimer.moveToThread(this);
to beginning of run() method of your thread from that point on your timer object will invoke the connected slot within the your thread.
When you first create the timer it will run within your main thread. By moving it to your own thread as above the moveToThread method will change the thread affinity of the timer object.
It is also worth mentioning this article
The biggest adjustment for me was to understand that threads in qt are used as an interface, and are not really intended for subclassing. With that being said, I would keep your class and and actual QThread separate. And then just use YourClass.moveToThread( &YourQtThread) to ensure your signals and slots are process on that thread.