How do I stop and start a loop in QT? - c++

I've been trying to figure out how to make the program stop in a for-loop and wait for a button to be clicked and the for-loop continues.
Isn't there any easy way to stop the loop like QSystem.stop() and in the button clicked function QSystem.star() and the loop continues.
In C++ you could use system("pause") or the program stopped when you used a cin<<. But how do i do this in QT?

Since the userinterface needs its code to run, if you halt event loop (which also means that any function that gets called from within the event loop is blocking, waiting for some event), you also halt the user interface, which means clicks into the window won't be processed. That's why in event based programming, which is what all UI kits do, it is essential to return to the main event handler loop as quickly as possible.
What you can do is create a second thread and wait on a condition variable. The GUI thread can signal that condition variable in the button click event slot.
In C++ you could use system("pause") or the program stopped
Exactly: The program is stopped. Which means it won't fetch events from the operating system. However receiving data from stdin is not an event. It's blocking on streamed I/O. Graphical user interfaces are event based though.
Note that conceptually it's not really impossible to think of a user interface to provide streaming I/O channels. However that doesn't work in single threaded programs. You need parallel execution (coroutines, threads, or such) for a concept like this to work.

You don't need threads, nested event loop will do the job.
int waitUntilSignalIsEmitted(QObject *sender, const char *signal) {
QEventLoop loop;
connect(sender, signal,
&loop, SLOT(quit()));
return loop.exec();
}
// usage:
while(yourLoopCondition) {
// some stuff
...
// pause here
waitUntilSignalIsEmitted(yourContinuationButton, SIGNAL(clicked()));
// loop continuation
...
}

Related

buttons on wxWidgets

I am programming a GUI with wxWidgets. I got a button to open a serial port and receive data. In there is a while(1) loop to constantly receive the data.
Now I want to do a "Disconnect" button to stop receiving.
Is there an event handler or a callback function to interrupt the while and jump out of the loop from the first button, when I press another button?
A wxButton sends a message when it is clicked. Create a handler for this message where you do your "interrruption".
Now, a loop can be only exited from its inner guts. I mean, inside the loop you should check a flag, and depending on the value of this flag continue or exit.
My advice is that you create a worker thread. When the button "connect" is clicked then you create the thread that receives data.
This thread checks an extern flag and finishes depending on the value of the flag.
The "disconnect" button click-handler just sets that extern flag to a value that makes the thread exits when it checks that flag.
Take a look at the thread sample provided with wxWidgets sources.
If you have a while(1) loop in the callback function for "button pressed", you will hang the UI. Callback functions must return quickly.
The quickest solution is to put the while(1) loop into a worker thread. That way your GUI won't hang.
The next problem is how to stop the loop. That's quite easy. Change the loop into:
while (keep_going.load()) {
....
where keep_going is of type std::atomic_bool. Then your "stop" button just calls keep_going.store(false).

Run the code continuously until "Stop" is pressed

I want to execute some code when I press a "Start" button and it have it continue running until I press "Stop".
However, with the following code once I press "Start", I can't press "Stop" anymore:
void MainWindow::on_pushButton_clicked()
{
if (ui->pushButton->text()=="Start") {
ui->pushButton->setText("Stop");
vec spectrum_sensed,Sn,sigma,alpha;
mat ydata;
condition=true;
while (condition) {
cvec uhd_samples = to_cvec(randn(Nsamples),randn(Nsamples));
ydata=spectrum->dft(uhd_samples,Ndft,Nband);
myplot->Plot_data(spectrum_sensed,Ndft);
}
}
else {
ui->pushButton->setText("Start");
condition=false;
myplot->clear_plot();
}
}
Qt's GUI runs in a single thread, and if your code blocks that thread, things like mouse clicks won't ever get handled (because the thread is busy doing nothing but calculating your data), and so your GUI freezes up.
As for how to change your program so that doesn't happen, you have a few options:
You could just throw a call to qApp->processEvents() into your calculation loop. That way Qt will get a chance to handle things like mouse clicks while you are calculating. That's the easiest way to go, but it can bite you if you're not careful -- for example if you've set up some other code so that a mouse click causes your MainWindow to be deleted, then you're likely to crash because after processEvents() returns it find itself executing in the on_pushButton_clicked() method of a now-deleted MainWindow object(!).
You could spawn a separate thread (using the QThread object) and run your calculation loop there. This is probably the most efficient approach, since on a multicore CPU it will let the GUI event loop run on one core while the calculations-loop simultaneously runs on another core, and so neither loop will slow the other one down. Note that this approach only works if your calculation loop doesn't touch any of the Qt GUI stuff -- Qt's GUI widgets are meant to be accessed only by the GUI thread, and if you try to examine them or modify them from a different thread, bad things will happen.
You could "unwrap" your loop so that it's no longer a synchronous loop but rather more like a state machine: That is, move the declarations of your calculation's state variables (spectrum_sensed, Sn, sigma, alpha, and ydata) out of the method, so that they are now member variables of the MainWindow class instead. Then write a Slot method that just does one iteration of your while loop (or maybe a small number of iterations, depending on how long each iteration takes), and then (within a few dozen milliseconds) calls QTimer::singleShot(0, this, SLOT(TheCalculationSlotMethodName()) and returns. That QTimer::singleShot() call will cause your calculation-slot-method to be called again on the next iteration of the Qt event loop, whereupon it can do a little bit more calculation. When the user clicks the "Stop" button, just have your on_stopButton_Pushed() slot set a boolean or something so that your calculation-method will know not to call QTimer::singleShot() anymore. I like this approach because there is little risk of race conditions or re-entrancy problems.

How can I stop a long for loop when the widget (QDialog) running it is closed without multithreading?

I have a quite lengthy foreach loop in a QDialog. It basically looks like this:
foreach (xxx, xxx) {
... doSomeStuff ...
QApplication::processEvents();
if (m_cancelMapLoading) {
break;
}
}
m_cancelMapLoading is set to true by clicking a "Cancel" button. The QApplication::processEvents(); makes this possible.
This works quite fine, but if the dialog is closed as long as that foreach loop still runs, it continues running. I tried to set m_cancelMapLoading to true in each function closing the dialog, but this does not help.
I also tried to test not only for m_cancelMapLoading being true, but also for isVisible(). This actually stops the dialog, but it re-opens it at once without the GUI elements in it.
Unfortunately, QtConcurrent::run etc. can't be used for the function, because the data structures that are manipulated by the foreach loop are not thread safe.
Is there a convenient way to solve this?
You can use a QTimer and Qt's parent-child structure to your advantage here. QTimer with a timeout value of zero has a special meaning in Qt
As a special case, a QTimer with a timeout of 0 will time out as soon
as all the events in the window system's event queue have been
processed. This can be used to do heavy work while providing a snappy
user interface:
So you could do something like
void Dialog::beginDoingStuff()
{
m_timer = new QTimer(this);
connect(m_timer, SIGNAL(timeout()), this, SLOT(processData());
m_timer->start(0);
}
void Dialog::processData()
{
// Perform one cycle of your process here
}
This will perform the processData() function in the same thread as the rest of the dialog, and when the dialog is destroyed by being closed, the timer will be deleted (because it's parent is the dialog), meaning the processing will stop.
A good and quite easy way to unload your GUI from heavy processing is assigning it to another thread or QtConcurrent.
You could then either poll a "should-I-terminate-yet?" variable or terminate the thread manually when it is no longer needed.
I highly recommend a parallel processing since offers better control rather than doing a "DoEvents"-like queue emptying.
We actually managed to solve the problem by connecting the dialog's finished signal to the click slot of the cancel button. This actually stops the loop in all circumstances.
We also introduced starting the function by a QTimer (for a nicer implementation not blocking the function where it's started), but this does not stop the loop (perhaps because we don't destroy the dialog when it's closed).
Thanks for all help :-)

QT : How to determine if the event processor is busy

In my current Qt application I am attempting to shut it down using
QCoreApplication::quit();
Now it takes more than a minute for the application to shutdown. I believe this is because the event processor of the main form is busy. My question is : Is there a way for me to determine what the cause of this might be. Here are somethings that I suspect
1-Queued Connections.
I have a lot of queued connections. Maybe some of those connections dont get processed
2-Event Loop.
May be the event loop is busy doing something that I dont know (expect)
Any suggestions on what I could do to check why the app takes so long to close ?
Update:
I tried QCoreApplication::hasPendingEvents() and that returns true
There's no such thing as queued connections that are "not" processed, or event loop being "busy". An event loop is, essentially, this (in C++ pseudocode):
forever {
while (! nativeEventQueue.isEmpty()) {
QueueEntry entry = nativeEventQueue.take_first().convert();
QCoreApplication::sendEvent(entry.object, entry.event);
delete entry.event;
}
while (! eventQueue.isEmpty()) {
QueueEntry entry(eventQueue.take_first());
QCoreApplication::sendEvent(entry.object, entry.event);
delete entry.event;
}
waitFor(eventQueue, nativeEvents);
}
All of the event processing is done by sending some QEvent to a QObject. That's all that the event loop does. Some events result in the signals being emitted. It's not the event loop that is busy, it's the code that runs in the QObject::event and overridden implementations! This code blocks the event loop, since when it runs, the event loop's code is in the same thread and is on the call stack - it can't run.
Your code in slots connected to signals in Qt widgets and other objects is really executed while QCoreApplication::sendEvent and QCoreApplication::notify is on the call stack, with the event loop (a QAbstractEventDispatcher) somewhere deeper in the call stack, and finally a QEventLoop under it.
If your code executes at a pace that is slower than the events are added to the queue, you will have problems.
This trivial example demonstrates such code. In real programs it'll be of course "obfuscated", but the problem often reduces to:
void Class::customEvent(QEvent * ev) {
...
QCoreApplication::postEvent(this, new EventFoo(...));
...
QCoreApplication::postEvent(this, new EventFoo(...));
...
}
The explicit event posting can be expressed very differently. For example, it could be you sending a signal to yourself:
void Class::mySlot() {
...
emit signal1();
...
emit signal2();
}
If both signal1 and signal2 are connected to mySlot through a queued connection, your application will run out of memory, as the event queue will only grow, never shrink. It may still appear responsive.

QThreads interruption with slots and signals

I have a class which contains QThread. In the initialization function of this class the thread should be started. This works correct. in the thread there I have a while(bool certainCondition){} this certainCondition should be changed by a signal/slot connection.
The problem is that during the while is running the signal/slot is not opened.
You are not running an event loop in your thread, or you are blocking for a long time in your while-loop. Your slot cannot be called until you have returned control to the event loop, which will happen after you have finished the while-loop.
As a workaround, you can try calling QCoreApplication::processEvents() inside your while-loop.
In order for signals/slots to work across threads, the event loop must run.
If you use a while loop, the event loop is never run, and hence signals are not received.
This is how you normally run the event loop:
void Thread::run()
{
...do something
exec(); //<<this runs the event loop
}
Now, your problem is that you want continuously run some code until some condition is met. In the above code, this won't work, because of the exec() call.
There are 2 possibilities to solve that (depending on what you want to achieve in your loop):
Use a QTimer, that fires let's say every 5 seconds, and calls a slot which executes your repeating code.
Use a QWaitCondition to check for a certain condition to be fulfilled; but then you cannot use signals and slots; instead you have to trigger the QWaitCondition.