Qt/C++: Checkable button and infinite loop - c++

I'm coding a Qt Gui and I'm trying to implement a new feature, I now the precise result I want to arrive at but not how to code it.
I'm trying to add a checkable button that when checked would run a function that would only stop when the button is unchecked, but every second a PaintArea I have on the window would be updated (letting me see how the multiple executions of my function are changing my data). It seem that I'll need to use some QThread objects, but just the part dealing with the button is already counter intuitive to me, I've been trying to play with the autoRepeatDelay and autoRepeatInterval without getting my hand on what they do and how they could be useful to me.
I guess that what I'm trying to code is not really original, would have an idea of the steps to implement it, or an example of a code?
Edit:
According to the first answers (thank you for them by the way) my question may not be clear. Putting on the side the thread thing, I'd like to implement an infinite loop that only starts when a pressbutton goes to pressed position (it's a checkable button) and stops only when leaving it. The first version I tried to do (with a while(button->isChecked() loop) would completely freeze as the application would be running the loop, the gui would freeze and the button couldn't be turned off (hence the idea of running it in a separate thread). Voila! I hope it's a clearer formulation. Thank you in advance.

Here's a simple skeleton of something that might work. Without knowing your exact requirements, it may or may not be right for your problem. Hopefully it will give you a few hints that do actually help.
void Ui::buttonPressedSlot(bool checked){
if (checked){
Processor *processor = new Processor;
connect(this, SIGNAL(abortCalculations()), processor, SLOT(abort()), Qt::QueuedConnection);
connect(processor, SIGNAL(updateNeeded()), this, SLOT(updateGui()), Qt::QueuedConnection);
QThreadPool::globalInstance()->start(processor);
} else {
emit abortCalculations(); // this is a signal in your UI class
}
}
You can then use the following for your calculations.
class Processor : public QObject, public QRunnable{ // QObject must always be first in multiple inheritance
Q_OBJECT
public:
~Processor();
void run();
public slots:
void abort();
void doCalculations();
signals:
void updateNeeded(); // connect this to the GUI to tell it to refresh
private:
QScopedPointer<QEventLoop> loop;
};
Processor::~Processor(){
abort();
}
void Processor::run() {
loop.reset(new QEventLoop);
QTimer timer;
connect(&timer, SIGNAL(timeout()), this, SLOT(doCalculations()));
timer.setInterval(1000);
timer.start();
loop->exec();
}
void Processor::abort(){
if (!loop.isNull()){
loop->quit();
}
}
void Processor::doCalculations(){
// do whatever needs to be done
emit updateNeeded();
}

I don't know if I really understand what you want to do, but I will try to answer.
First, you want a Button that send a start & stop info to control a thread. You can use a checkbox to begin. This check box send a signal when its state changes. Connect this signal to a slot that perform start thread and stop according to the boolean sent.
Second, in you thread you need to launch the events loop. After, set a timer that call you repaint after every timeout.
Hope it helped.
PS: take care of execution context with you thread and Qt's objects.

Related

QDialog box showing blank when MainWindow thread is busy

I am working on a Qt-C++ based front-end app for a Raspberry Pi powered robot. I am using Qt version 5.9 along with libraries QSerialPort and Pigpio. In my app, when I give the run command for a command sequence to the robot, my Raspberry Pi starts a serial communication with a microcontroller in which it sends some message and then waits to receive a response. This sending and waiting causes the Mainwindow thread to freeze up. I am trying to build in a emergency stop functionality, which would stop the command execution in the middle of the run process.
Towards that effort, I tried to push my serial communication part to a separate thread(QThread). It didn't work out. Now I am trying to build the emergency stop part into a QDialog box that opens up when I give the run command, which contains a emergency stop QPushbutton. The Dialog box is being run in non-modal form. But in my current code, when I give the run command, a dialog box does open up, but the dialog box is completely blank and then closes up when the run command ends(which is intentional). I'll share some screenshots of the appearance.
Can you suggest where I might be going wrong? Or is there a better approach to this issue? Any criticism and suggestions are welcome!
Thanks!
One shouldn't block the main thread in the Qt. Everytime you call the blocking function, your GUI freezes, as well as Dialog boxes.
One solution is to use signal/slots. They blend really well into Qt. But doing a complicated request/response logic would require a huge state machine usually prone to errors.
Sometimes it is better to leave this code blocking, create a plain chain of request/response code, and put it in another non-GUI thread. Then use the signal to notify the main thread about the job result.
In order to stop the execution it is possible to use an atomic and check it between blocking steps. The biggest time delay before exiting the working function is the biggest delay of the single blocking function. You should carefully tune the timeouts. Or you can write your own function, which emulates timeout and a stop condition. It should check if incoming data is available in an infinite loop and check fro stop condition on each iteration, which must be a timeout AND a stop condition variable.
// pseudocode here
while (true) {
if (stopCondition) return; // check for emergency condition
it (currentTime - startTime > timeout) return;
if (serial->dataReady()) break;
}
auto data = serial->getData();
If a step can block forever, then this method can't be used.
There is an example with QtConcurrent framework, which demonstrates the use of QFuture and the work of a function in a separate thread without blocking the main thread. You can put all your communication logic inside it.
The code is example only!
#ifndef WORKERCLASS_H
#define WORKERCLASS_H
#include <QObject>
#include <QtConcurrent/QtConcurrent>
#include <QFuture>
class WorkerClass : public QObject
{
Q_OBJECT
public:
explicit WorkerClass(QObject *parent = nullptr) : QObject(parent) {
connect(&futureWatcher, &QFutureWatcher<void>::finished, [this] () {
emit workFinsihed();
});
}
void startWork(int value) {
atomic = 0;
future = QtConcurrent::run(this, &WorkerClass::workFunction, value);
futureWatcher.setFuture(future);
}
void stopWork() {
atomic = 1;
}
private:
QFuture<void> future;
QFutureWatcher<void> futureWatcher;
void workFunction(int value) {
for (int i = 0; i < value; ++i) {
if (atomic) return;
}
return;
};
QAtomicInt atomic{0};
signals:
void workFinsihed();
};
#endif // WORKERCLASS_H

Qt connect in constructor not connecting?

A google search gives these as the top three results:
Qt: Connect inside constructor - Will slot be invoked before object is initialized?
Qt can I connect signals/slots to self in constructor?
QT Connect Signal Slot and initialize in constructor
According to those, it seems like it ought to "just work" like anything else. But this code doesn't:
EditorList::EditorList(..., QWidget* parent) :
QWidget(parent)
{
...
Processing* processing = Processing::getInstance();
connect(this, SIGNAL(reorderDelete(DataSequence*,ListType,QList<int>)), processing, SLOT(reorderDelete(DataSequence*,ListType,QList<int>)));
...
buttonDelete = new QPushButton(this);
connect(buttonDelete, SIGNAL(clicked(bool)), this, SLOT(buttonDeleteClick()));
...
}
...
void EditorList::buttonDeleteClick()
{
...
QList<int> locations;
...
emit reorderDelete(mySequence, myListType, locations); //breakpoint 1 here
}
//-----------------------------------------------------------------
void Processing::reorderDelete(DataSequence* sequence, ListType listType, QList<int> locations)
{
if(sequence) //breakpoint 2 here
{
sequence->reorderDelete(listType, locations);
}
}
The reason for this structure, instead of calling mySequence->reorderDelete directly, is to have it done in Processing's thread instead of the UI's. I hope I haven't stripped out too much detail to show the problem; this is a rather large project.
When I click my delete button, I hit breakpoint 1 (so far, so good), but I don't hit breakpoint 2. My other signals/slots work across threads, but their connects are not in constructors. I want to make this one automatic so that every instance is "just connected" without having to remember to do it. Can I not do that?
Okay, I got it. Leaving up for others to find.
According to this, my ListType enum was blocking the system from making the connection. It only works with system-known datatypes because emitting a SIGNAL actually stores a copy for the SLOT(s) to read later. I knew that, but I thought it was more like a stack frame that could take anything. Apparently not.
It also works to put a call to qRegisterMetaType<ListType>("ListType"); somewhere before the connect. (I put it in my main window's constructor.) This makes the datatype known so that the connection can work anyway.
I'm hitting both breakpoints now.
Make sure you have used Q_OBJECT macros in your class

Read a file in background to update Qjsonvalue

I need to update the content of a field on my QWidget via a JSON file (updated in real time). I've read about functions readLine() and readAll() of QFile, but when I try a loop like :
while(true):
jsfile.readLine()
creation of objects, update of values, display etc ...
I lost the focus on my window. But I want to keep the control of the application with my buttons and obviously to watch the evolution of the JSON values.
I have thought that Qt manages itself the events and keeps the focus on the current window, but like I've said, it's not the case.
Is there a good solution (multi threads maybe) to use my window while the application reads the file (with new informations in real time)?
(With the constraint "real time" I can't read the whole file every time and I've no choice about the format of this file)
Update
I tried the thread method.
So, I choose to create my thread instance into the main (with my main window) and connect here. But, when I run the program, I've this error :
no matching member function for call to 'connect'
Reader reader;
QObject::connect(controler, SIGNAL(ready()),
reader, SLOT(received()));
According to this error, I've thought that the reason was main don't inherits of Object, and so, I've move the connection ans the creation of thread instance into my main window.
Reader reader;
QObject::connect(reader, SIGNAL(newobject(QJsonObject)),
this, SLOT(displayJSON(QJsonObject)));
With this one, I've the same error while I've already connect lot of widget into this class without any error.
What can be the problem ?
Update 2
I've a solution when I give as argument my main window (controler) in reader's constructor and connect into this one but, if possible, I would an explanation for the previous problem.
The current problem that I have is that signals are emit well but slots are executed after the end the application (so after the end of the thread's execution and not during)
This isn't really the subject of this topic so we can close this one.
You can use QThread (Qt documentation: QThread) class to create a thread, which will read your file. The main thread will execute your GUI application and it will be available during file reading.
You can find a simple example in documentation for creating your thread:
class WorkerThread : public QThread
{
Q_OBJECT
void run() Q_DECL_OVERRIDE {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &s);
};
void MyObject::startWorkInAThread()
{
WorkerThread *workerThread = new WorkerThread(this);
connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
You can modify this example for your purpose. For example, WorkerThread for your task may be something like this:
class WorkerThread : public QThread
{
Q_OBJECT
void run() Q_DECL_OVERRIDE {
while(!stopFlag)
{
// read JSON file to QByteArray. Use QFile and QTextStream
// use QJsonDocument to read JSON content
// find what is new in JSON
emit signalSomethingNew(/*parameters*/);
QThread::currentThread()->msleep(/*timeout*/);
}
}
signals:
void signalSomethingNew(/*parameters*/);
};
At the end you must implement slot on your QWidget for signalSomethingNew(/*parameters*/) and make connection:
connect(yourThread, &WorkingThread::signalSomethingNew, youWidget, &YouWidget::yourSlot);
For working with JSON data: QJsonDocument
I'm interpreting your question as "my application is unresponsive whilst doing work" rather than "my focus jumped to another window" - please comment if you meant something different.
You have a choice of options:
Create and run a background QThread to do the work. Have it emit signals (connected to your widgets using Qt::QueuedConnection - the default) when it has results to display.
This is a good solution when the worker has a lot of computation to do, or needs all the input to be read before it can start. It works very well when the target system has processors available with no other work to do.
Use a QSocketNotifier to signal your GUI thread when some of the input becomes available (note that the name is misleading - it actually works on all kinds of file descriptor, not just sockets).
This is appropriate when the algorithm is simple and incremental - i.e. if a small chunk of input can be read and processed quickly.
Incorporate periodic calls to processEvents() in your algorithm:
auto *const dispatcher = QThread::currentThread()->eventDispatcher;
while (line = json.readLine()) {
doSomethingWith(line);
if (dispatcher)
dispatcher->processEvents();
}
This won't work unless you can modify the algorithm like this - if the loop is in somebody else's (closed) code, then you'll need one of the other solutions.

Qt - updating main window with second thread

i have an multithreaded qt application. when i am doing some processes in mainwindow.cpp, at the same time, i want to update mainwindow.ui from other thread.
i have mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include "mainwindow.h"
class mythread : public QThread
{
public:
void run();
mythread( MainWindow* ana );
MainWindow* ana;
private:
};
#endif // MYTHREAD_H
mythread.cpp
mythread::mythread(MainWindow* a)
{
cout << "thread created" << endl;
ana = a;
}
void mythread::run()
{
QPixmap i1 (":/notes/pic/4mdodiyez.jpg");
QLabel *label = new QLabel();
label->setPixmap(i1);
ana->ui->horizontalLayout_4->addWidget(label);
}
but the problem is that, i cannot reach the ana->ui->horizontalLayout_4->addWidget(label);
how can i do that?
but the problem is that, i cannot reach the
ana->ui->horizontalLayout_4->addWidget(label);
Put your UI modifications in a slot in your main window, and connect a thread signal to that slot, chances are it will work. I think only the main thread has access to the UI in Qt. Thus if you want GUI functionality, it must be there, and can be only signaled from other threads.
OK, here is a simple example. BTW, your scenario doesn't really require to extend QThread - so you are better off not doing it, unless you really have to. That is why in this example I will use a normal QThread with a QObject based worker instead, but the concept is the same if you subclass QThread:
The main UI:
class MainUI : public QWidget
{
Q_OBJECT
public:
explicit MainUI(QWidget *parent = 0): QWidget(parent) {
layout = new QHBoxLayout(this);
setLayout(layout);
QThread *thread = new QThread(this);
GUIUpdater *updater = new GUIUpdater();
updater->moveToThread(thread);
connect(updater, SIGNAL(requestNewLabel(QString)), this, SLOT(createLabel(QString)));
connect(thread, SIGNAL(destroyed()), updater, SLOT(deleteLater()));
updater->newLabel("h:/test.png");
}
public slots:
void createLabel(const QString &imgSource) {
QPixmap i1(imgSource);
QLabel *label = new QLabel(this);
label->setPixmap(i1);
layout->addWidget(label);
}
private:
QHBoxLayout *layout;
};
... and the worker object:
class GUIUpdater : public QObject {
Q_OBJECT
public:
explicit GUIUpdater(QObject *parent = 0) : QObject(parent) {}
void newLabel(const QString &image) { emit requestNewLabel(image); }
signals:
void requestNewLabel(const QString &);
};
The worker object is created and moved to another thread, then connected to the slot that creates the labels, then its newLabel method is invoked, which is just a wrapper to emit the requestNewLabel signal and pass the path to the image. The signal is then passed from the worker object/thread to the main UI slot along with the image path parameter and a new label is added to the layout.
Since the worker object is created without parent in order to be able to move it to another thread, we also connect the thread destroyed signal to the worker deleteLater() slot.
First and foremost, "you're doing it wrong". Normally you want to create a class derived from a QObject and move that class to a new thread object instead of deriving your class from a Qthread
Now to get onto the specifics of your question, you're not able to directly modify the ui elements of your main GUI thread from a separate thread. You have to connect a signal from your 2nd thread to a slot in your main thread. You can pass any data that you need through this signal/slot connection but you're unable to directly modify the ui element (which in all honestly you probably do not want to if you intend to keep the frontend of your app separate from the backend). Checkout Qt's signal and slot documentation for a whole lot more information
how can i do that?
You've already got the answers to what you should be doing, but not a why, so I'm going to add a why.
The reason you don't modify GUI elements from another thread is because GUI elements are usually not thread-safe. This means that if both your main GUI thread and your worker thread update the UI, you cannot be certain of the order of what happened when.
For reading data generally this can sometimes be fine (e.g. checking a condition) but generally you do not want this to be case. For writing data, this is almost always the source of very, very stressful bugs which occur "at random".
Another answer has remarked on good design principles - not only does constraining your GUI logic to one thread and firing signals to talk to it get rid of your race condition issues, but it also forces you to compartmentalize your code nicely. Presentation logic (the display bit) and data processing logic can then be cleanly separated out, which makes maintaining the two much easier.
At this stage you might think: heck, this threads business is farrrrrr too much work! I'll just avoid that. To see why this is a bad idea, implement a file copy program in a single thread with a simple progress bar telling you how far along the copy is. Run it on a large file. On Windows, after a while, the application will "go white" (or on XP I think it goes gray) and will be "not responding". This is very literally what is happening.
GUI applications internally mostly work on the variation of "one big loop" processing and dispatching messages. Windows, for example, measures response time to those messages. If a message takes too long to get a response, Windows then decides it is dead, and takes over. This is documented in GetMessage().
So whilst it may seem like quite a bit of work, Signals/Slots (an event-driven model) is basically the way to go - another way to think of this is that it is totally acceptable for your threads to generate "events" for the UI too - such as progress updates and the like.

Multi-threading in Qt problematic?

I have been learning Qt for a while and a few days ago I decided to go on multi-threading by QThread. I have been following this person. Since he says that subclassing QThread is not the appropriate way but by using QObject is. I am following his method. But he has created another class which inherits from QObject. I decided to make a few changes:
class myclass
{
private:
dowork();
private slots:
slota();
slotb();
slotc();
}
myclass::dowork()
{
QThread lett;
QThread latt;
QThread pltt;
QObject lethread;
connect(&lett, SIGNAL(started()), this, SLOT(slota()));
lethread.moveToThread(&lett);
QObject lathread;
connect(&latt, SIGNAL(started()), this, SLOT(slotb()));
lathread.moveToThread(&latt);
QObject plthread;
connect(&pltt, SIGNAL(started()), this, SLOT(slotc()));
plthread.moveToThread(&pltt);
lett.start();
latt.start();
pltt.start();/*
lett.wait();
latt.wait();
pltt.wait();*/
while(lett.isRunning())
{
//qDebug() << "Still Running!";
}
lett.quit();
}
If I run the program it keeps running while loop infinitely! It doesn't come out of that at all.
I used qdebug inside the implementation of the 3 slots to check whether it is entering them or not, and surprisingly none of the slots gets called. Why is that so?
If I remove the comments for .wait then the program pauses.
What is wrong in this method? I want to avoid that extra class as my program is very small.
while(lett.isRunning())
{
//qDebug() << "Still Running!";
}
lett.quit();
Terribly wrong. The current thread is busy waiting and will be eating all the time. But this is not your problem. Your problem is certainly that the main event loop has probably not started yet, ie you didn't do QApplication.exec() yet.
Qt uses events to start threads, and when you do use movetoThread, start, specific events are queued in the current thread (ie the thread executing these methods). If the main event loop has already started, then will be processed as soon as they can. But in your case I bet that you main function is :
int main(){
QApplication app();
myclass onlyclassIwanttomake;
onlyclassIwanttomake.dowork();
app.exec(); <----HERE!!!
}
The thread will be started when the main thread executes app.exec();. When you are busy waiting, you are preventing the main thread to process the events required to start your
events.
EDIT: Well, another issue is that
lett.start();
latt.start();
pltt.start();
start 3 threads which are started, and stay idle forever. They are not doing anything, but they are running (even if you remove your loop).
This is a entry written about Qt threading. Please take the time to read it.