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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With