I have one problem which I can't solve using the Internet. I have label and I set pixmap on it. I put it on main window (widget) where is button (QPushButton) too. I want to do that:
If I click on the button then on this pixmap will be drawn circles continuously
If I click this button for second then drawing must be stopped by function pause()
The second one is easy, it's empty slot:
void pause() {}
But at first I've tried to use loop
while(true)
draw();
but it crashed a program (loop).
Any idea how to solve it?
You should never block the main thread. This will cause the OS to consider your application has hanged. In fact it is a good practice to move any code, whose execution takes more than 50 milliseconds to another thread to keep the main thread responsive, especially in the case of Qt, where it is also the GUI thread.
You should use an event driven approach, which will not block the thread.
class YourClass : public QObject { // QObject or derived
Q_OBJECT
public:
YourClass() { connect(&timer, &Timer::timeout, this, &YourClass::draw); }
public slots:
void start() { timer.start(33); }
void pause() { timer.stop(); }
private:
QTimer timer;
void draw() { ... }
};
When start() is invoked, draw() will be called every 33 miliseconds. pause() will effectively stop that until start() is invoked again. You can control the rate at which draw() is invoked by adjusting the timer's interval, by default it is 0, which in the case of drawing is overkill, you should adjust for a desired framers per second. In the example above, the it is 33 milliseconds, or roughly 30 FPS.
You should then call draw() with some time interval, instead of halting the whole GUI thread with it.
For that, there's QTimer:
QTimer timer; // should be a member, a pointer optionally - you then do new Qtimer(this);
connect(&timer, &QTimer::timeout, draw);
timer.start(500); // in milliseconds
// assuming you are calling this from member function of QObject-deriving class
// and draw is a non-member function
If you know to do the connections, you can connect it to anything...
The same can be done with QThread and putting it to sleep in that loop.
Anyhow, I don't get how an empty pause() stops the drawing. Aren't you halting your application again? Just do timer.stop();.
Related
Here I am explaining my problem statement in detail and the efforts I have put so far
A) Problem Statement : During printing if 'Stop Printing' pushbutton is pressed, the printing should stop at that moment!
B) My Work :
1. StartPrinitng_Pressed :
void MainWindow :: on_StartPrinitng_Pressed()
{QSqlquery studentList;
studentList("SELECT Name, address FROM class WHERE Roll No = some variable")
while(studentList.next())
{
Name=studentList.value(0).toString();
address=studentList.value(1).toString();
QTimer:: singleShot(1000,this,SLOT(StopNow())); //calling stopNow function
if(StopPrintingNow==0)
{ //** I am printing the fetched data (in a string) by setting GPIO pins HIGH **// }
}
}
2. StopPrinting_Pressed :
void MainWindow::on_StopPrinting_Pressed()
{StopPrintingNow=1;}
3. StopNow Function Declaration :
void MainWindow::StopNow()
{
if(StopPrintingNow==1)
{ //** I have reset all serials ports; Break; **// }
else if(StopPrintingNow==0)
{ QTimer::singleShot(1000,this,SLOT(on_startPrinting_pressed())); }
}
C) Flow of program execution : As and when "StartPrinting" pushbutton is pressed, the query shown in my question executes which fetches data from database and perform simultaneous printing.
D)Problem Faced -
1.GUI is getting hanged while printing, hence StopPrinting button doesn't respond.
Qtimer is not calling "StopNow function " while printing (though I have called it at correct position)enter image description here
Handling of timers and button presses is both covered by the Qt event loop -- which is blocked while you are looping over that SQL query. You have two options:
1) Periodically dispatch events in your while loop.
This is as simple as
qApp->processEvents();
But you have to be careful, however: any events you trigger due to user interaction (or a timer) will block and your while loop will not run until the event is finished. In your case especially, you could end up running a second copy of your on_StartPrinitng_Pressed function.
2) Do the printing on a separate thread.
This involves some more code, but the gist of it is that you create a SqlPrinter object with a startPrinting slot and stopPrinting slot. You then create a QThread and change its owner thread to that thread. Slot invocations will happen across the thread boundary and all will be fine.
class SqlPrinter : public QObject {
Q_OBJECT
public:
SqlPrinter(QObject* parent = nullptr) : QObject(parent) {}
public slots:
void startPrinting();
void stopPrinting();
};
In your main code, then do something like this, assuming that you have the two buttons named MainWindow_StartButton and MainWindow_StopButton:
QThread* printerThread = new QThread(qApp);
SqlPrinter* printer = new SqlPrinter;
printer->moveToThread(printerThread);
printerThread->start();
QObject::connect(MainWindow_StartButton, &QPushButton::clicked, printer, &SqlPrinter::StartPrinting);
QObject::connect(MainWindow_StopButton, &QPushButton::clicked, printer, &SqlPrinter::StopPrinting);
Don't forget to clean up SqlPrinter afterwards!
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
I'm trying to update the main window by calling updateGUI function in a thread every 500 ms. The window is displayed but not updated with the new values unless I close the window. When I do so, a new window is opened with the new value. I found this question but it didn't answer my question. I knew that (as stated in qt documentation)
QApplication::exec enters the main event loop and waits until
exit() is called.
I tried to use processEvents() but the main window is opened and closed repeatedly and very fast that I can't even see it. Here is my code:
float distanceToObject;
bool objectDetected;
Modes currentMode;
void timerStart(std::function<void(void)> func, unsigned int interval)
{
std::thread([func, interval]()
{
while (true)
{
auto x = std::chrono::steady_clock::now() + std::chrono::milliseconds(interval);
func();
std::this_thread::sleep_until(x);
}
}).detach();
}
int updateGUI(void)
{
int argc = 0;
char **argv = NULL;
QApplication a(argc, argv);
MainWindow w;
// Set text of a label
w.setDistance(QString::number(distanceToObject));
// Also update objectDetected and currentMode values
w.show();
//a.processEvents();
return a.exec();
}
void sendMsg(void)
{
// Send heartbeat signal to another device
}
void receiveMsg(void)
{
// Read messages from the other device and update the variables
// These two values change continuously
objectDetected = true;
distanceToObject = 5.4;
}
void decide(void)
{
// The core function of the program. Takes relatively long time
// Run a decision-making algorithm which makes decisions based on the values received from the other device.
// Update some variables according to the made decisions
currentMode = Auto;
// Execute functions according to the made decisions.
setMode(currentMode);
}
int main(void)
{
timerStart(updateGUI, 500);
timerStart(sendMsg, 1000);
timerStart(receiveMsg, 10);
timerStart(decide, 500);
}
How can I update the main window with the variables' values correctly?
Your thread does not update the MainWindow, but it does create an entirely new QApplication and MainWindow on every iteration. Your thread should be stuck inside QApplication::exec until you quit the application (e.g. by closing the window). Only then should your thread's loop make further progress.
In general, you must be very careful when doing updates from outside the main thread, since typically GUI operations must be performed inside the main thread.
Think about using QThread, which already comes with its own event loop, which you can use to notify/update your window using a respective slot.
Without further details about what you are actually trying to achieve, it is not possible to give you further direction. I, at least, recommend that you create your QApplication and MainWindow inside the main thread (e.g. main). Then it depends what you are trying to 'update'. If you need to progress some data, then you can do that within your second thread and send the results to your MainWindow instance using signal-slot. If you need to draw onto the window, then this either has to be done in the main thread directly, or you might find a way to render into a separate buffer (i.e. QImage) from within your thread and then send this buffer to the main thread for drawing it into the window.
I try to sketch how something like this can be done. Notice, however, that this it neither complete nor compilable, but merely an outline.
First, you have your MainWindow and add to it a signal, that notifies all observers to start doing their work (will become clear in a moment). Furthermore, you add slots that will be invoked whenever one of your values changes. Those slots run in the main thread (and are members of the MainWindow) and thus can update the window however they need to:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
// constructors and stuff
void startWorking()
{
emit startWorkers();
}
public slots:
void onModeChanged(Modes m)
{
// update your window with new mode
}
void onDistanceChanged(float distance)
{
// update your window with new distance
}
signals:
void startWorkers();
};
Next, you build a Worker class, that encapsulates all the 'background work' you like to do (basically what your thread did in your original code):
class Worker : public QObject
{
Q_OBJECT
public:
// constructors and stuff
public slots:
void doWork()
{
while(!done)
{
// do stuff ...
Modes m = // change mode
emit modeModified(m);
// do stuff ...
float distance = // compute distance
emit distanceModified(distance);
// do stuff ...
}
}
signals:
void modeModified(Modes m);
void distanceModified(float distance);
};
Note, that Worker must inherit QObject and that your doWork method must be a public slot. Furthermore, you add a signal for each of the values you like your MainWindow to be informed about. No implementation for them is needed, since it is generated by the Qt MOC (Meta Object Compiler). Whenever one of the respective values changes, simply emit the corresponding signal and pass the new value.
Lastly, you put everything together:
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow window;
// create a worker object
Worker* worker = new Worker;
// connect signals and slots between worker and main window
QObject::connect(worker, &Worker::modeModified,
&window, &MainWindow::onModeChanged);
QObject::connect(worker, &Worker::distanceModified,
&window, &MainWindow::onDistanceChanged);
QObject::connect(&window, &MainWindow::startWorkers,
worker, &Worker::doWork);
// create a new thread
QThread* thread = new QThread;
// send worker to work inside this new thread
worker->moveToThread(thread);
thread->start();
// show window and start doing work
window.show();
window.startWorking();
// start main loop
int result = app.exec();
// join worker thread and perform cleanup
return result;
}
Alright, let's go through it. First, you create your QApplication and MainWindow inside your main thread. Next, create an instance of your Worker object (could create multiple here). Then you connect the signals of the worker to the slots of the window and vice versa. Once these connections are established, whenever you emit a signal, the connected slot is invoked by Qt (and passed values are transmitted). Notice, that this connection works across thread boundaries. Whenever a signal is emitted from a thread different then the receiving object's thread, Qt will send a message, which is processed in the receiving object's thread.
Then you tell Qt that you want your worker to live inside another thread using QObject::moveToThread. See here for a very detailed explanation of how to correctly use QThread and objects inside it.
The rest is then simple. show your window and start processing. Here different ways are possible. I just call the startWorking method here, which then emits the startWorkers signal, which is connect to the worker's doWork method, such that doWork will start executing after this signal is received by the other thread.
You then call QApplication::exec which runs the main thread's event loop, where all these signals are processed by Qt. Once your application is closed (e.g. by calling quit or closing the main window) the exec method returns and you are back in main. Notice, that you need to correctly close the thread (e.g. by sending an addition signal that stops the while loop) and join it. You also should delete all the allocated objects (worker, thread). I omitted this here for simplicity of the code example.
Answering your Question
I have many functions, e.g., updateClips and mavReceive that should be called periodically and run independently from each other. I should create a different Worker class for each function, as each has different signals, and a QThread object for each of these functions, right? I don't need startTimer() anymore? If yes, how can I control the calling interval for each function (used to be done in startTimer()
from the comment:
The answer greatly depends on what exactly you mean by "should be called periodically". Who is supposed to call them? The user? Or should they just be executed periodically?
So in principle, you can have multiple workers in one thread. However, if they are supposed to do work all the time (spin in a while loop) it does not make sense, since one is running and all others are blocked. In that case you would have one thread for each worker.
If I understand you correctly, you are interested in updating something periodically (e.g. every 500ms). In that case I highly recommend using the QTimer. You can set an interval and then start it. The timer will then periodically emit the timeout signal, which you can connect to whatever function (more precisely slot) you want to have executed.
An updated version of the Worker could look like this:
class Worker : public QObject
{
Q_OBJECT
public:
Worker()
{
QObject::connect(&modeTimer_, &QTimer::timeout,
this, &Worker::onModeTimerTimeout);
QObject::connect(&distanceTimer_, &QTimer::timeout,
this, &Worker::onDistanceTimerTimeout);
modeTimer_.start(500); // emit timeout() every 500ms
distanceTimer_.start(100); // emit timeout() every 100ms
}
public slots:
void onModeTimerTimeout()
{
// recompute mode
Modes m = // ...
emit modeModified(m);
}
void onDistanceTimerTimeout()
{
// recompute distance
float distance = // ...
emit distanceModified(distance);
}
signals:
void modeModified(Modes m);
void distanceModified(float distance);
private:
QTimer modeTimer_;
QTimer distanceTimer_;
};
Notice, the connections established in the constructor. Whenever one of the timers times out, the connected slot is invoked. This slot then may compute whatever it needs to and afterwards send the result back to the MainWindow in the main thread using the same signal as before.
So, as you see, you can have multiple timers / re-computations / update signals within one Worker (and thus, one thread). However, the crucial point for an implementation is, how long the computations take. If they take very long (e.g. nearly as long as the intervals) then you should think about using multiple threads to speed up the computation (meaning: perform one computation in each thread). As I slowly seem to get a clearer picture of what you want to achieve, I am wondering whether it is only about these periodic updates that you 'misused' the thread for in your question. If this is indeed the case, then you do not need that thread and Worker at all. Then simply add the timers to your MainWindow and connect their timeout signal to the respective slot of the MainWindow directly.
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.
I have a class, which is an abstraction of some device.
class Device
{
public:
...
void Start();
void Stop();
void MsgLoop();
signals:
void sMsgArrived();
}
Start() and Stop() are called from GUI thread. Start() begins new thread, which runs MsgLoop(). It looks like this:
void MsgLoop()
{
forever {
if(SUCCESS == ReadMsg()) //synchronous, non-blocking
{
ProcessMsg(); //quite fast
emit sMsgArrived(); //this signal is connected with a slot in GUI thread
}
}
}
When Stop() is called, program should return from MsgLoop() and stop the thread. How can I implement this with QThread without subclassing it?
Generally you have to decide who will be responsible for managing the thread. Is it the Device or the main window? Or possibly some device manager. In your case the Device should probably manage its own thread, so if you don't want to subclass it, use composition:
class Device : QObject
{
Q_OBJECT
public:
Device(QObject * parent = NULL);
void Start();
void Stop();
private slots:
void MsgLoop();
signals:
void sMsgArrived();
private:
QThread thread;
bool stopThread;
};
Device::Device(QObject * parent) : QObject(parent)
{
moveToThread(&thread);
connect(&thread, SIGNAL(started()), this, SLOT(MsgLoop()));
}
void Device::Start()
{
stopThread = false;
thread.start();
}
void Device::Stop()
{
stopThread = true;
thread.wait(); // if you want synchronous stop
}
void Device::MsgLoop()
{
// your loop
while(!stopThread)
if(SUCCESS == ReadMsg())
{
ProcessMsg();
emit sMsgArrived();
}
QThread::currentThread->quit();
}
NOTE: the thread stopping will only work if ReadMsg really is non-blocking. If you later decide to switch to blocking read (and that would probably be appropriate for most cases), you will have to figure out another way how to stop your thread.
If you look at this link you can see that it is possible to run a method in a separate thread without subclassing a QThread.
However what you are asking is running a message loop forever.
If you follow the given example you can run your loop without subclassing but the QThread object will never enter into its own message loop cause it will never return from your slot. So here is an example but I think it would be a bad design
class Device : public QObject
{
Q_OBJECT
public:
Device(QObject* parent = 0);
~Device();
public Q_SLOTS:
void MsgLoop();
};
QThread* thread = new QThread;
Device* device = new Device;
void Widget::onBtnStartClicked()
{
device->moveToThread(thread);
//This will call start method of Device
connect(thread, SIGNAL(started()), device, SLOT(MsgLoop()));
//This will start the event loop of thread
thread->start();
}
void Widget::onBtnStopClicked()
{
//Tells the thread to exit
thread->exit(0);
}
I am afraid you have to subclass a QThread if you want to run a forever loop.
IMHO you shouldn't. Polling requires being in a forever loop. You must do this in QThread's run function so there is no way to re-implement a function without sub-classing first. Even if you were to try and workaround it with a single shot timer I don't recommend it. You are better off(this is how i like to do it) sub-classing QThread, calling moveToThread(), not call exec() and put a forever loop in run. For an example of this look at the Fortune Blocking Client example from qt. If you don't call moveToThread() on QThread then the QThread object still resides in the GUI main thread and they both share the same event loop (which is bad when using polling functions). Calling moveToThread(QThread) without calling exec() means the QThread will not have an event loop(which is good in your case). Calling exec() would start it's own event loop but is not used for polling schemes and you would leave the run function.