I work in Qt and when I press the button GO I need to continuously send packages to the network and modify the interface with the information I receive.
The problem is that I have a while(1) in the button so the button never finishes so the interface is never updated. I thought to create a thread in the button and put the while(){} code there.
My question is how can I modify the interface from the thread? (For example how can I modify a textBox from the thread ?
Important thing about Qt is that you must work with Qt GUI only from GUI thread, that is main thread.
That's why the proper way to do this is to notify main thread from worker, and the code in main thread will actually update text box, progress bar or something else.
The best way to do this, I think, is use QThread instead of posix thread, and use Qt signals for communicating between threads. This will be your worker, a replacer of thread_func:
class WorkerThread : public QThread {
void run() {
while(1) {
// ... hard work
// Now want to notify main thread:
emit progressChanged("Some info");
}
}
// Define signal:
signals:
void progressChanged(QString info);
};
In your widget, define a slot with same prototype as signal in .h:
class MyWidget : public QWidget {
// Your gui code
// Define slot:
public slots:
void onProgressChanged(QString info);
};
In .cpp implement this function:
void MyWidget::onProgressChanged(QString info) {
// Processing code
textBox->setText("Latest info: " + info);
}
Now in that place where you want to spawn a thread (on button click):
void MyWidget::startWorkInAThread() {
// Create an instance of your woker
WorkerThread *workerThread = new WorkerThread;
// Connect our signal and slot
connect(workerThread, SIGNAL(progressChanged(QString)),
SLOT(onProgressChanged(QString)));
// Setup callback for cleanup when it finishes
connect(workerThread, SIGNAL(finished()),
workerThread, SLOT(deleteLater()));
// Run, Forest, run!
workerThread->start(); // This invokes WorkerThread::run in a new thread
}
After you connect signal and slot, emiting slot with emit progressChanged(...) in worker thread will send message to main thread and main thread will call the slot that is connected to that signal, onProgressChanged here.
P.s. I haven't tested the code yet so feel free to suggest an edit if I'm wrong somewhere
So the mechanism is that you cannot modify widgets from inside of a thread otherwise the application will crash with errors like:
QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
Segmentation fault
To get around this, you need to encapsulate the threaded work in a class, like:
class RunThread:public QThread{
Q_OBJECT
public:
void run();
signals:
void resultReady(QString Input);
};
Where run() contains all the work you want to do.
In your parent class you will have a calling function generating data and a QT widget updating function:
class DevTab:public QWidget{
public:
void ThreadedRunCommand();
void DisplayData(QString Input);
...
}
Then to call into the thread you'll connect some slots, this
void DevTab::ThreadedRunCommand(){
RunThread *workerThread = new RunThread();
connect(workerThread, &RunThread::resultReady, this, &DevTab::UpdateScreen);
connect(workerThread, &RunThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
The connection function takes 4 parameters, parameter 1 is cause class, parameter 2 is signal within that class. Parameter 3 is class of callback function, parameter 4 is callback function within the class.
Then you'd have a function in your child thread to generate data:
void RunThread::run(){
QString Output="Hello world";
while(1){
emit resultReady(Output);
sleep(5);
}
}
Then you'd have a callback in your parent function to update the widget:
void DevTab::UpdateScreen(QString Input){
DevTab::OutputLogs->append(Input);
}
Then when you run it, the widget in the parent will update each time the emit macro is called in the thread. If the connect functions are configured properly, it will automatically take the parameter emitted, and stash it into the input parameter of your callback function.
How this works:
We initialise the class
We setup the slots to handle what happens with the thread finishes and what to do with the "returned" aka emitted data because we can't return data from a thread in the usual way
we then we run the thread with a ->start() call (which is hard coded into QThread), and QT looks for the hard coded name .run() memberfunction in the class
Each time the emit resultReady macro is called in the child thread, it's stashed the QString data into some shared data area stuck in limbo between threads
QT detects that resultReady has triggered and it signals your function, UpdateScreen(QString ) to accept the QString emitted from run() as an actual function parameter in the parent thread.
This repeats every time the emit keyword is triggered.
Essentially the connect() functions are an interface between the child and parent threads so that data can travel back and forth.
Note: resultReady() does not need to be defined. Think of it as like a macro existing within QT internals.
you can use invokeMethod() or Signals and slots mechanism ,Basically there are lot of examples like how to emit a signal and how to receive that in a SLOT .But ,InvokeMethod seems interesting .
Below is example ,where it shows How to change the text of a label from a thread:
//file1.cpp
QObject *obj = NULL; //global
QLabel *label = new QLabel("test");
obj = label; //Keep this as global and assign this once in constructor.
Next in your WorkerThread you can do as below:
//file2.cpp (ie.,thread)
extern QObject *obj;
void workerThread::run()
{
for(int i = 0; i<10 ;i++
{
QMetaObject::invokeMethod(obj, "setText",
Q_ARG(QString,QString::number(i)));
}
emit finished();
}
you start thread passing some pointer to thread function (in posix the thread function have the signature void* (thread_func)(void*), something equal under windows too) - and you are completely free to send the pointer to your own data (struct or something) and use this from the thread function (casting pointer to proper type). well, memory management should be though out (so you neither leak memory nor use already freed memory from the thread), but this is a different issue
Related
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.
Structure Of Application:
MainWindow -> ProcessingThread(QThread) - > QProcess for Python Script
In the Run/Exec loop of Processing Thread I would like to interact with the process.
How do I go about it?
Current Problem:
I know both ProcessingThread(QThread) and its Run loop run inside different threads. Hence if I initialize the QProcess in QThread constructor I am unable to interact with the process because of following error:
QSocketNotifier: Socket Notifiers cannot be enabled or disabled from
another thread
and if I try to initialize the process in the Run Loop I get the following error:
QObject: Cannot create children for a parent that is in a different
thread
(Parent is ProcessingThread(0x984b2a0), parent's thread is QThread(0x940e180)),
current thread is ProcessingThread(0x984b2a0)
If I initialize the QProcess in ProcessingThread constructor, I am able to interact with the script perfectly.
Any suggestions?
Update: Also The reason for using QThread is because I am performing image processing, the Processing Threads keeps fetching images from camera. Some of these images need to be further processed by the Python script running in QProcess.
Update 2: CODE
void MainWindow::MainWindow(QWidget *parent)
{
...
debugProcessingThread = new DebugProcessingThread();
}
class DebugProcessingThread : public QThread
{
Q_OBJECT
...
private:
qProcess *myprocess;
}
DebugProcessingThread::DebugProcessingThread()
{
...
myProcess = new QProcess(this);
myProcess->start("python abc.py");
connect(myProcess, SIGNAL(started()), this, SLOT(processStarted()));
connect(myProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError()));
connect(myProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));
myProcess->waitForStarted();
}
void DebugProcessingThread::processError()
{
qDebug("PROCESS ERROR");
qDebug() << myProcess->errorString();
}
void DebugProcessingThread::readStandardOutput()
{
qDebug("READ DATA");
qDebug(myProcess->readAll().toStdString().c_str());
myProcess->write("out.txt\n");
}
void DebugProcessingThread::processStarted()
{
qDebug("Process has started");
}
The above code works perfectly.
But I want to send and receive data from function:
void DebugProcessingThread::run()
{
myProcess->write("out.txt\n");
// This Throws socket Error
}
Keep long story short, you shouldn't instantiate anything you going to use in your new thread in the constructor, as every object instantiated there will get an affinity of the thread where your QThread object is created, common practice is either not to subclass QThread at all, just use QObject and moveToThread, and then connect some slot like init() to QThread started() signal, so you can do all initialisation inside the init() which will run inside a new thread, or if for whatever reasons you need QThread subclassing instantiate everything in run().
Also pay attention that QThread itself is nothing more nothing less then a wrapper of your real thread and stays as an object in a thread where you created it.
This question already has answers here:
How to execute a functor or a lambda in a given thread in Qt, GCD-style?
(5 answers)
Closed 6 years ago.
Im my mainthread, I have a Qt window running, which is calling my background thread (network service) and is eventually expecting responses which should be reflected in the UI:
// runs in main (GUI) thread
void QTServer::onButtonClick(){
srv->request(msg,
[this]
(std::shared_ptr<message> msg){
this->ui.txtResponse->setText("received a response" + msg.data());
});
}
The network service is as follows:
std::function<void(std::shared_ptr<message>)> delegate_;
void NetworkService::request(message& msg,std::function<void(std::shared_ptr<message> msg)> fn)
{
// send the request to the socket and store the callback for later
// ...
this->delegate_ = fn;
}
void NetworkService::onResponseReceived(std::shared_ptr<message> responseMsg)
{
// is called from the background thread (service)
// Here I would like to call the lambda function that the service stored somewhere (currently as an std::func member)
// psuedo: call In Main Thread: delegate_(responseMsg);
}
How does that work? Does it even work?
I know that you can use QMetaObject::invokeMethod(this, "method", Qt::QueuedConnection to call a function in the mainthread, so I tried the following:
void NetworkService::onResponseReceived(std::shared_ptr<message> responseMsg)
{
QMetaObject::invokeMethod(this, "runInMainThread", Qt::QueuedConnection, QGenericArgument(), Q_ARG(std::function<void(std::shared_ptr<message>)>, delegate_));
}
How do I pass the responseMsg here as an argument for _delegate?
void QTServer::runInMainThread(std::function<void(std::shared_ptr<message>)> f) {
f();
}
How to get rid of "No function with these arguments" error?
remove QGenericArgument() - it's internal helper class.
also you have to register your own types in order to use Q_ARG or send data as void* then cast it back.
Q_ARG(void*, delegate_)
2nd question - f is function which takes one argument - std::shared_ptr, and f() - call without argument, so add default argument
I believe the recommended way for what you are trying to achieve in QT is by using signals and slots in combination with QThread. For example:
MyObject * myObject = new MyObject(); //your worker
QThread * myThread = new QThread(); //your thread
myObject->moveToThread(myThread);
QObject::connect(myThread, SIGNAL(started()), myObject, SLOT(startWorking())); //when thread starts, invoke the working method
QObject::connect(myObject, SIGNAL(stoppedWorking()), this, SLOT(stoppedWorking())); //when worker signals it finished, invoke slot in main
QObject::connect(myObject, SIGNAL(stoppedWorking()), myThread, SLOT(quit())); //quit the thread when worker signals that it finished
QObject::connect(myObject, SIGNAL(gproxyExiting()), gproxy, SLOT(deleteLater())); //cleanup
QObject::connect(myThread, SIGNAL(finished()), myThread, SLOT(deleteLater())); //cleanup
This way the whole lifecycle is managed automatically for you and you can define whatever signals inside the worker and slots on the main thread to communicate with each other.
I have a class in the main thread which initiates another thread. From the created thread, I send a signal to main thread to get the current documentElement of the QWebView and main thread replies to to the thread and sets the local QWebElement variable in the thread. So, here is some code:
Thread has:
...
public slots:
void setCurrentElement(QWebElement aElement);
signals:
void sgGetCurrentElement(void);
private:
QWebElement currentElement;
Main thread has:
...
public slots:
void onGetCurrentElementReceived(void);
signals:
void sgResponseToGetElement(QWebElement aElement);
After creating the thread, I connect the signals to slots like:
connect(insExtractor, SIGNAL(sgGetCurrentElement()), this, SLOT(onGetCurrentElementReceived()));
connect(this, SIGNAL(sgResponseToGetElement(QWebElement)), insExtractor, SLOT(setCurrentElement(QWebElement)));
Once the main thread receives a signal from the thread, it does the following:
void targetClass::onGetCurrentElementReceived(void)
{
emit sgResponseToGetElement(insWebView->page()->mainFrame()->documentElement());
}
The setter in the thread does the following:
void createdThread::setCurrentElement(QWebElement aElement)
{
currentElement = aElement;
}
Here is the problem:
My target is to find the first form element whose id is submitForm. There is such a form in the element, no problem there.
If I write the following line before emitting the signal in the main thread:
QWebElement form_found = currentElement.findFirst("form[id='submitForm']");
form_found doesn't return null and it finds the form element. No problem.
If I write the same code right after I set the currentElement in setCurrentElement in the thread, it does the same and it finds the form. However, if I do the same right after I emit the very first signal again in the thread, it returns null. Here is the code:
void createdThread::startExtracting(void)
{
sgGetCurrentElement();
QThread::msleep(2000);
QWebElement form_found = currentElement.findFirst("form[id='submitForm']");
}
So, form_found is coming null. Could anyone tell me why it is returning null? I put logs everywhere and it is being called after it is set in the setter. What is wrong with this?
My suspect is that you are stopping the event loop of the thread doing the sleep.
Threads in Qt are a bit tricky. Take a look at this, it makes all these questions very clear.
I'd say you should use the Element when you are sure you got it and that's on setCurrentElement. Why don't you start the extraction on that method ?
I have done an application with some threads. Everything seems to work ok if I call my stopConsumer inside a keypressedEvent. But If I call it inside a destructor of closeEvent.. it fails.
My QThread class that has a run method like this one:
void Consumer::run()
{
forever {
// do something something
// do something something
// do something something
//-------------------------------- check for abort
abortMutex.lock();
if(abort) {
abortMutex.unlock();
qDebug() << "abort..";
break;
} abortMutex.unlock();
//-------------------------------- check for abort
}
qDebug() << "Consumer > emit finished()";
emit finished();
}
void Consumer::stopConsume() {
abortMutex.lock();
abort = true;
abortMutex.unlock();
}
and a method in the MainWindow:
void initConsumers()
{
consumer1 = new Consumer(....);
connect(consumer1, SIGNAL(finished()),
this, SLOT(deleteConsumer()));
consumer1->start();
}
void stopConsumer() {
if(consumer1!=NULL) {
qDebug() << "stopConsumer";
consumer1->stopConsume();
}
}
If I have a keypressed that calls stopConsumer.. it's ok, deleteConsumer is reached.
If I call stopConsumer inside the MainWindow destructor or inside a MainWindow closeEvent.. the slot deleteConsumer is never reached!
Any ideas?
Given that the Consumer class and your MainWindow have different thread affinities, the call you make to connect inside initConsumers() is likely using a Qt::QueuedConnection, which means that the deleteConsumer() slot won't get called immediately.
If you would like to ensure that the consumer gets deleted from the destructor of your main window (or equivalently, from a close event), one possible solution is to call stopConsume() on the consumer, then wait until the thread is no longer running (see http://qt-project.org/doc/qt-5.1/qtcore/qthread.html#isRunning), then call deleteConsumer() directly.
Update
Here's an example of what I described above:
consumer1->stopConsume();
consumer1->wait();
deleteConsumer();
It's not advisable to switch the connection type to Qt:DirectConnection since that will cause the deleteConsumer() function to be called from the body of Consumer::run(), which will likely crash your application.
Part of the problem here is that you're deriving from QThread, which is not how it is supposed to be used. You can read about why deriving from QThread is wrong here.
Instead, what you should be doing is deriving your class from QObject, creating a QThread object and moving the derived QObject instance to that thread.
class Consumer : public QObject
{
...
signals:
void finished();
private slots:
void run();
}
QThread pThread = new QThread;
Consumer pObject = new Consumer;
// move the pObject to the thread
pObject->moveToThread(pThread);
You can then control the thread with signals and slots.
// assuming you've added a run slot function to the Consumer class
connect(pThread, SIGNAL(started()), pObject, SLOT(run()));
connect(pObject, SIGNAL(finished()), pThread, SLOT(quit()));
connect(pObject, SIGNAL(finished()), pObject, SLOT(deleteLater()));
// Note the thread cleans itself up here, but if the app is quitting,
// waiting on the thread to finish may be required instead
connect(pThread, SIGNAL(finished()), pThread, SLOT(deleteLater()));
And start the thread: -
pThread->start();
Used this way, it also enables multiple objects to be moved to a single new thread, rather than creating a new thread per object instance.