How do I create a Window in different QT threads?
If you need to create QWidget(or some other gui component(s)) in different(non-main) thread(s) you can implement it in such way:
Create simple wrapper which holds gui component:
// gui component holder which will be moved to main thread
class gui_launcher : public QObject
{
QWidget *w;
// other components
//..
public:
virtual bool event( QEvent *ev )
{
if( ev->type() == QEvent::User )
{
w = new QWidget;
w->show();
return true;
}
return false;
}
};create QApplication object in main thread
another thread body:
..
// create holder
gui_launcher gl;
// move it to main thread
gl.moveToThread( QApplication::instance()->thread() );
// send it event which will be posted from main thread
QCoreApplication::postEvent( &gl, new QEvent( QEvent::User ) );
..be happy, :)
Create QMainWindow from different thread
Qt will only let you create widgets from the main GUI thread, this is explicitly mentioned in the docs (emphasis mine):
As mentioned, each program has one thread when it is started. This
thread is called the "main thread" (also known as the "GUI thread" in
Qt applications). The Qt GUI must run in this thread. All widgets and
several related classes, for example QPixmap, don't work in secondary
threads. A secondary thread is commonly referred to as a "worker
thread" because it is used to offload processing work from the main
thread.
How to create QtQuick window outside the main thread
If you want a QQuickView to live outside the main()
thread, then you must:
- Create a new
std::thread
(NOT aQThread
, because it is aQObject
so it mustn't be created before yourQGuiApplication
) - Run an
init()
function in that thread. Let it instantiate yourQGuiApplication
and start the event loop. - Create your
QQuickView
in that thread too. - Ensure that all of your GUI objects are accessed from that thread only.
- Ensure that your
main()
thread doesn't create anyQObject
s until after yourQGuiApplication
has been created in your other thread.
See How to avoid Qt app.exec() blocking main thread for more details.
How can I start a GUI window from a QThread?
Yes, you are going about this in the wrong way. GUIs, due to platform limits, are single threaded systems. You cannot create, change and manage GUI objects on different threads - everything must be done on one thread (normally, the GUI thread).
Qt has two mechanisms for dealing with worker threads and the GUI: queued signals and slots, and the QCoreApplication::postEvent() handler.
More details are in the comprehensive Qt threading document: http://doc.qt.io/qt-5/thread-basics.html
Qt - updating main window with second thread
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.
QtCreator C++ create thread in main window
As discussed in the comments, in this use-case it's preferable to not use threading, but exploit the Qt event loop and signal-slot mechanism. Here is the skeleton of the MainWindow and the SerialReciver classes, and how they are wired together in main.cpp. For simplicity, the SerialReceiver class just emits the signal every second with the current time, which will be appended to the editfield's content in the main window.
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPlainTextEdit>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void onSerialMessage(const QString &msg);
private:
QPlainTextEdit mTextField;
};
mainwindow.cpp:
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
mTextField.setReadOnly(true);
setCentralWidget(&mTextField);
}
MainWindow::~MainWindow()
{
}
void
MainWindow::onSerialMessage(const QString &msg)
{
mTextField.appendPlainText(msg);
}
#endif // MAINWINDOW_H
serialreceiver.h:
#ifndef SERIALRECEIVER_H
#define SERIALRECEIVER_H
#include <QObject>
#include <QTimer>
class SerialReceiver : public QObject
{
Q_OBJECT
public:
explicit SerialReceiver(QObject *parent = nullptr);
signals:
void newMsg(const QString &msg);
public slots:
void onSerialReceived();
private:
QTimer mTimer;
};
#endif // SERIALRECEIVER_H
serialreceiver.cpp:
#include "serialreceiver.h"
#include <QDateTime>
SerialReceiver::SerialReceiver(QObject *parent) : QObject(parent)
{
mTimer.setInterval(1000);
mTimer.setSingleShot(false);
connect(&mTimer, &QTimer::timeout,this,&SerialReceiver::onSerialReceived);
mTimer.start();
}
void
SerialReceiver::onSerialReceived()
{
QDateTime now = QDateTime::currentDateTime();
emit newMsg(now.toString());
}
and main.cpp:
#include "mainwindow.h"
#include "serialreceiver.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
SerialReceiver receiver;
MainWindow w;
QObject::connect(&receiver, &SerialReceiver::newMsg,
&w,&MainWindow::onSerialMessage);
w.show();
return a.exec();
}
Does creating a new Qt Window with no parent also create a new thread?
- No new thread is created for
mainWindow
- The
mainWindow
event loop is executed in scope ofa.exec()
- it blocks until application exits (for example - last top-level window is closed).
So mainWindow
does not go out of scope, because it is main
that executes everything.
Check it using code like:
std::cout << "starting application event loop" << std::endl;
const int ret = a.exec();
std::cout << "after exec" << std::endl; // or any other code here
return ret;
From QApplication doc:
Enters the main event loop and waits until exit() is called, then returns the value that was set to exit() (which is 0 if exit() is called via quit()).
Related Topics
Console Output in a Qt Gui App
Significance of Parentheses in Decltype((C))
How to Pass Std::String to a Dll
How to Return a Char Array from a Function
Specify Template Parameters at Runtime
What Is Dynamic Initialization of Object in C++
Reinterpret_Cast VS. C-Style Cast
Why Don't the Std::Fstream Classes Take a Std::String
"Inline" Keyword VS "Inlining" Concept
Why Does Libc++'s Implementation of Std::String Take Up 3X Memory as Libstdc++
How to Use Covariant Return Types with Smart Pointers
Error: Variable "Cannot Be Implicitly Captured Because No Default Capture Mode Has Been Specified"
What Happens When You Call Data() on a Std::Vector<Bool>
Why Is There an Implicit Type Conversion from Pointers to Bool in C++
Random Output Different Between Implementations
How to Read Output from Cmd.Exe Using Createprocess() and Createpipe()