I want to filter some unwanted events sent to my worker QThread by QCoreApplication::postEvent(...), before it actually processed in event loop.
When is event actually filtered by event filter: in postEvent() in the calling thread or later in QThread event loop?
I think answer is "in event loop", but i couldn't find answer to that exact question in qt docs.
Both the worker and its event filter need to be living in the same thread. Events are picked up by the thread's event loop and passed through the filter right before being delivered to their receiver QObject (when the filter allows this). Here is an example that demonstrates this behavior:
#include <QtCore>
//a thread that can be destroyed at any time
//see http://stackoverflow.com/a/25230470
class SafeThread : public QThread{
using QThread::run;
public:
explicit SafeThread(QObject *parent = nullptr):QThread(parent){}
~SafeThread(){ quit(); wait(); }
};
struct MyEvent : public QEvent {
static const QEvent::Type myType = static_cast<QEvent::Type>(2000);
MyEvent():QEvent(myType){}
};
//worker QObject that handles MyEvent by printing a message
class Worker : public QObject {
public:
explicit Worker(QObject *parent = nullptr):QObject(parent){}
bool event(QEvent *event) {
if(event->type() == MyEvent::myType) {
qInfo() << "event in thread: " << QThread::currentThreadId();
return true;
}
return QObject::event(event);
}
};
class EventFilter : public QObject {
public:
explicit EventFilter(QObject *parent = nullptr):QObject(parent){}
bool eventFilter(QObject *watched, QEvent *event) {
if(event->type() == MyEvent::myType) {
qInfo() << "filter in thread: " << QThread::currentThreadId();
return false; //do not filter the event
}
return QObject::eventFilter(watched, event);
}
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
//create worker and thread
Worker worker;
EventFilter filter;
SafeThread thread;
filter.moveToThread(&thread);
worker.moveToThread(&thread);
worker.installEventFilter(&filter);
thread.start();
qInfo() << "calling postEvent from thread: " << QThread::currentThreadId();
QCoreApplication::postEvent(&worker, new MyEvent());
QTimer::singleShot(1000, &a, &QCoreApplication::quit);
return a.exec();
}
Output should look something like:
calling postEvent from thread: 0xAAAA
filter in thread: 0xBBBB
event in thread: 0xBBBB
The filtering must be performed on event delivery, because the filter expects the target object to exist and have an accessible state. Such existence and state can only be guaranteed while the event is being delivered. It is not safe to use QObject's methods, save a select few, from other threads, thus in general when posting an event, it's not possible to safely access the target object!. It's only possible to do so when the object's lifetime is guaranteed, and thread-safe methods are used to access the state, and it's done in a fashion that doesn't lead to deadlocks.
Related
QObjects can easily become threadless, when their work thread finishes ahead of them. When this happens, Qt doesn't release their timer ids, even though the timers are not active anymore. Thus, a QBasicTimer::stop: Failed. Possibly trying to stop from a different thread warning appears. It has mostly cosmetic consequences, but does indicate a timer id leak, and thus a workaround would be nice to have. The following example triggers the problem:
#include <QtCore>
int main(int argc, char *argv[]) {
static_assert(QT_VERSION < QT_VERSION_CHECK(5,11,0), "");
QCoreApplication app(argc, argv);
QObject object;
object.startTimer(1000);
QThread workThread;
workThread.start();
object.moveToThread(&workThread);
QTimer::singleShot(500, &QCoreApplication::quit);
app.exec();
workThread.quit();
workThread.wait();
}
It'd be nice if the workaround didn't have to make any modifications to how the timers are allocated, i.e. that there would be no extra tracking of timers needed beyond what Qt already does.
A simple solution is to prevent the problem: if the object is about to become threadless, move it to the thread handle's parent thread, and then when the thread itself is about to be destructed, reestablish the object's timers to prevent the warning.
QObject's moveToThread implementation has two parts:
The QEvent::ThreadChange is delivered to the object from moveToThread. QObject::event uses this event to capture and deactivate the timers active on the object. Those timers are packaged in a list and posted to the object's internal _q_reactivateTimers method.
The event loop in the destination thread delivers the metacall to the object, the _q_reregisterTimers runs in the new thread and the timers get reactivated in the new thread. Note that if _q_reregisterTimers doesn't get a chance to run, it will irrevocably leak the timer list.
Thus we need to:
Capture the moment the object is about to become threadless, and move it to a different thread, so that the QMetaCallEvent to _q_reactivateTimers won't be lost.
Deliver the event in the correct thread.
And so:
// https://github.com/KubaO/stackoverflown/tree/master/questions/qbasictimer-stop-fix-50636079
#include <QtCore>
class Thread final : public QThread {
Q_OBJECT
void run() override {
connect(QAbstractEventDispatcher::instance(this),
&QAbstractEventDispatcher::aboutToBlock,
this, &Thread::aboutToBlock);
QThread::run();
}
QAtomicInt inDestructor;
public:
using QThread::QThread;
/// Take an object and prevent timer resource leaks when the object is about
/// to become threadless.
void takeObject(QObject *obj) {
// Work around to prevent
// QBasicTimer::stop: Failed. Possibly trying to stop from a different thread
static constexpr char kRegistered[] = "__ThreadRegistered";
static constexpr char kMoved[] = "__Moved";
if (!obj->property(kRegistered).isValid()) {
QObject::connect(this, &Thread::finished, obj, [this, obj]{
if (!inDestructor.load() || obj->thread() != this)
return;
// The object is about to become threadless
Q_ASSERT(obj->thread() == QThread::currentThread());
obj->setProperty(kMoved, true);
obj->moveToThread(this->thread());
}, Qt::DirectConnection);
QObject::connect(this, &QObject::destroyed, obj, [obj]{
if (!obj->thread()) {
obj->moveToThread(QThread::currentThread());
obj->setProperty(kRegistered, {});
}
else if (obj->thread() == QThread::currentThread() && obj->property(kMoved).isValid()) {
obj->setProperty(kMoved, {});
QCoreApplication::sendPostedEvents(obj, QEvent::MetaCall);
}
else if (obj->thread()->eventDispatcher())
QTimer::singleShot(0, obj, [obj]{ obj->setProperty(kRegistered, {}); });
}, Qt::DirectConnection);
obj->setProperty(kRegistered, true);
}
obj->moveToThread(this);
}
~Thread() override {
inDestructor.store(1);
requestInterruption();
quit();
wait();
}
Q_SIGNAL void aboutToBlock();
};
int main(int argc, char *argv[]) {
static_assert(QT_VERSION < QT_VERSION_CHECK(5,11,0), "");
QCoreApplication app(argc, argv);
QObject object1, object2;
object1.startTimer(10);
object2.startTimer(200);
Thread workThread1, workThread2;
QTimer::singleShot(500, &QCoreApplication::quit);
workThread1.start();
workThread2.start();
workThread1.takeObject(&object1);
workThread2.takeObject(&object2);
app.exec();
}
#include "main.moc"
This approach can be easily extended to dynamically track all children of obj as well: Qt provides sufficient events to do such tracking.
Hold the timer id to be killed from within thread - by object:
int id = object.startTimer(1000);
QThread workThread;
workThread.start();
object.moveToThread(&workThread);
QTimer::singleShot(500, &QCoreApplication::quit);
QObject::connect(&workThread, &QThread::finished, [&](){object.killTimer(id);});
...
How about moving the object back to the main thread...
class Object : public QObject
{
public:
using QObject::QObject;
virtual ~Object() {
qDebug()<<"Object"<<QThread::currentThread()<<this->thread();
if(thread() == Q_NULLPTR)
moveToThread(QThread::currentThread());
}
};
#include <QtCore>
int main(int argc, char *argv[]) {
static_assert(QT_VERSION < QT_VERSION_CHECK(5,11,0), "");
QCoreApplication app(argc, argv);
Object object;
object.startTimer(1000);
QThread workThread;
workThread.start();
object.moveToThread(&workThread);
QTimer::singleShot(500, &QCoreApplication::quit);
qDebug()<<"main"<<QThread::currentThread()<<object.thread();
app.exec();
workThread.quit();
workThread.wait();
}
Is there a way to consume future slots (and stop them from executing) in one of many slots connected to the same signal?
My goal here is to emit a signal with a message to many QObjects and consume (stopping iteration to future slots) when the QObject in which the message belongs to finds it.
From what I understand in the Qt Documentation:
If several slots are connected to one signal, the slots will be
executed one after the other, in the order they have been connected,
when the signal is emitted.
I want to be able to stop this process from within a slot.
Suggestions?
No, there's no way to do it, and you should not think of it this way. The sender should perform the same no matter what number of slots are connected to a signal. That's the basic contract of the signal-slot mechanism: the sender is completely decoupled from, and unaware of, the receiver.
What you're trying to do is qualified dispatch: there are multiple receivers, and each receiver can process one or more message types. One way of implementing it is as follows:
Emit (signal) a QEvent. This lets you maintain the signal-slot decoupling between the transmitter and the receiver(s).
The event can then be consumed by a custom event dispatcher that knows which objects process events of given type.
The objects are sent the event in the usual fashion, and receive it in their event() method.
The implementation below allows the receiver objects to live in other threads. That's why it needs to be able to clone events.
class <QCoreApplication>
class <QEvent>
class ClonableEvent : public QEvent {
Q_DISABLE_COPY(ClonableEvent)
public:
ClonableEvent(int type) : QEvent(static_cast<QEvent::Type>(type)) {}
virtual ClonableEvent * clone() const { return new ClonableEvent(type()); }
}
Q_REGISTER_METATYPE(ClonableEvent*)
class Dispatcher : public QObject {
Q_OBJECT
QMap<int, QSet<QObject*>> m_handlers;
public:
Q_SLOT void dispatch(ClonableEvent * ev) {
auto it = m_handlers.find(ev->type());
if (it == m_handlers.end()) return;
for (auto object : *it) {
if (obj->thread() == QThread::currentThread())
QCoreApplication::sendEvent(obj, ev);
else
QCoreApplication::postEvent(obj, ev.clone());
}
}
void addMapping(QClonableEvent * ev, QObject * obj) {
addMapping(ev->type(), obj);
}
void addMapping(int type, QObject * obj) {
QSet<QObject*> & handlers = m_handlers[type];
auto it = handlers.find(obj);
if (it != handlers.end()) return;
handlers.insert(obj);
QObject::connect(obj, &QObject::destroyed, [this, type, obj]{
unregister(type, obj);
});
m_handlers[type].insert(obj);
}
void removeMapping(int type, QObject * obj) {
auto it = m_handlers.find(type);
if (it == m_handlers.end()) return;
it->remove(obj);
}
}
class EventDisplay : public QObject {
bool event(QEvent * ev) {
qDebug() << objectName() << "got event" << ev.type();
return QObject::event(ev);
}
public:
EventDisplay() {}
};
class EventSource : public QObject {
Q_OBJECT
public:
Q_SIGNAL void indication(ClonableEvent *);
}
#define NAMED(x) x; x.setObjectName(#x)
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
ClonableEvent ev1(QEvent::User + 1);
ClonableEvent ev2(QEvent::User + 2);
EventDisplay NAMED(dp1);
EventDisplay NAMED(dp12);
EventDisplay NAMED(dp2);
Dispatcher d;
d.addMapping(ev1, dp1); // dp1 handles only ev1
d.addMapping(ev1, dp12); // dp12 handles both ev1 and ev2
d.addMapping(ev2, dp12);
d.addMapping(ev2, dp2); // dp2 handles only ev2
EventSource s;
QObject::connect(&s, &EventSource::indication, &d, &Dispatcher::dispatch);
emit s.indication(&ev1);
emit s.indication(&ev2);
return 0;
}
#include "main.moc"
If connection was in one thread, I think that you can throw an exception. But in this case you should be catch any exception during emit a signal:
try {
emit someSignal();
} catch(...) {
qDebug() << "catched";
}
But I think that it's bad idea. I'll would be use event dispatching for this.
I'm new in Qt and have a question.
I have QLabel and QLineEdit objects, and when QLabel text is clicked on, I want to set this text in QLineEdit.
Also I have read that QLabel has not clicked signal.
Can you explain how can I do this and write code for me ?!
Either style another type of QWidget such as a specific QPushButton to look like a QLabel and use its clicked() signal or inherit QLabel yourself and emit your own clicked() signal.
See this example:
https://wiki.qt.io/Clickable_QLabel
If you choose the latter option you can pass the text in the signal. Then connect the necessary signals/slots up between the QLabel and the QLineEdit like so:
QObject::connect(&label, SIGNAL(clicked(const QString& text)),
&lineEdit, SLOT(setText(const QString& text)));
A simple way to accomplish that, without a need for any subclassing, is a signal source that monitors the events on some object and emits relevant signals:
// main.cpp - this is a single-file example
#include <QtWidgets>
class MouseButtonSignaler : public QObject {
Q_OBJECT
bool eventFilter(QObject * obj, QEvent * ev) Q_DECL_OVERRIDE {
if ((ev->type() == QEvent::MouseButtonPress
|| ev->type() == QEvent::MouseButtonRelease
|| ev->type() == QEvent::MouseButtonDblClick)
&& obj->isWidgetType())
emit mouseButtonEvent(static_cast<QWidget*>(obj),
static_cast<QMouseEvent*>(ev));
return false;
}
public:
Q_SIGNAL void mouseButtonEvent(QWidget *, QMouseEvent *);
MouseButtonSignaler(QObject * parent = 0) : QObject(parent) {}
void installOn(QWidget * widget) {
widget->installEventFilter(this);
}
};
The emit keyword is an empty macro, Qt defines it as follows:
#define emit
It is for use by humans as a documentation aid prefix only, the compiler and moc ignore it. As a documentation aid, it means: the following method call is a signal emission. The signals are simply methods whose implementation is generated for you by moc - that's why we have to #include "main.moc" below to include all the implementations that moc has generated for the object class(es) in this file. There's otherwise nothing special or magical to a signal. In this example, you could look in the build folder for a file called main.moc and see the implementation (definition) of void MouseButtonSignaler::mouseButtonEvent( .. ).
You can then install such a signaler on any number of widgets, such as a QLabel:
int main(int argc, char ** argv) {
QApplication app(argc, argv);
MouseButtonSignaler signaler;
QWidget w;
QVBoxLayout layout(&w);
QLabel label("text");
QLineEdit edit;
layout.addWidget(&label);
layout.addWidget(&edit);
signaler.installOn(&label);
QObject::connect(&signaler, &MouseButtonSignaler::mouseButtonEvent,
[&label, &edit](QWidget*, QMouseEvent * event) {
if (event->type() == QEvent::MouseButtonPress)
edit.setText(label.text());
});
w.show();
return app.exec();
}
#include "main.moc"
You need to create one Custom Label class, which will inherit QLabel. Then you can use MouseButtonRelease event to check clicking of Label and emit your custom signal and catch in one SLOT.
Your .h file will be as below:
class YourLabelClass : public QLabel{
signals:
void myLabelClicked(); // Signal to emit
public slots:
void slotLabelClicked(); // Slot which will consume signal
protected:
bool event(QEvent *myEvent); // This method will give all kind of events on Label Widget
};
In your .cpp file, your constructor will connect signal & slot as below :
YourLabelClass :: YourLabelClass(QWidget* parent) : QLabel(parent) {
connect(this, SIGNAL(myLabelClicked()), this, SLOT(slotLabelClicked()));
}
Remaining event method and SLOT method will be implemented as below:
bool YourLabelClass :: event(QEvent *myEvent)
{
switch(myEvent->type())
{
case(QEvent :: MouseButtonRelease): // Identify Mouse press Event
{
qDebug() << "Got Mouse Event";
emit myLabelClicked();
break;
}
}
return QWidget::event(myEvent);
}
void YourLabelClass :: slotLabelClicked() // Implementation of Slot which will consume signal
{
qDebug() << "Clicked Label";
}
For Changing a Text on QLineEdit, you need to create a Custom Class and share object pointer with custom QLabel Class. Please check test code at this link
In the above example the header needs Q_OBJECT:
class YourLabelClass : public QLabel{
Q_OBJECT
signals:
I have created a custom QObject class called EncodeThread, which looks as follows:
class EncodeThread : public QObject {
Q_OBJECT
public:
void set(SWSL::Video* v, QStringList f, QDir vDir);
void run();
public slots:
void encode();
signals:
void encodeProgress(int i);
private:
SWSL::Video* video;
QStringList files;
QDir videoDir;
};
As may be obvious, this class is used for encoding a video using an external library. Encode() contains the actual encoding routine, run() is a function I added while troubleshooting, though it's obviously non-functional:
void EncodeThread::run() {
if (currentThread() != this) {
// caller is in different thread.
QMetaObject::invokeMethod(this, "encode", Qt::QueuedConnection);
}
else {
encode();
}
}
The problem is when I use a QThread and the moveToThread() function on the EncodeThread instance, namely that nothing seems to happen. No data is written, and the instance never emits the signal which should save the encoded file to disk.
encThread.set(video, files, videoDir);
connect(&encThread, SIGNAL(encodeProgress(int)), cookVideoProgress, SLOT(setValue(int)));
connect(&encThread, SIGNAL(finished()), this, SLOT(videoCookEnd()));
connect(this, SIGNAL(videoEncode()), &encThread, SLOT(encode()));
encThread.moveToThread(&thread);
thread.start();
The above is how the whole setup is started. EncThread and thread variables are declared in the MainWindow class. I have made the set() function of EncodeThread call encode() after attempts to call encode() from the main thread using signals and QMetaObject failed.
I'm not new to threading, having used native Windows and Linux threads, as well as those of various cross-platform implementations, but QThreads really seem to baffle me. Any suggestions are more than welcome :)
Probably way to late to be any help to you, but here's a little demo program that puts an EncoderThread class to work. It probably doesn't quite mesh with your design (which your question only had fragments of), but it demonstrates running an object instance on its own thread and wiring 2 objects on different threads via signals/slots to let them communicate:
#include <stdio.h>
#include <QObject>
#include <QThread>
#include <QtCore/QCoreApplication>
// QSleeper is just a toy utility class that makes the
// protected QThread::sleep() family of functions
// publicly accessible. It's only use is for demo
// programs like this
class Sleeper : QThread
{
public:
static void sleep(unsigned long secs) { QThread::sleep(secs); }
static void msleep(unsigned long msecs) { QThread::msleep(msecs); }
static void usleep(unsigned long usecs) { QThread::usleep(usecs); }
};
// an Encoder class that maintains itself on is own thread
class EncodeThread : public QObject {
Q_OBJECT
public:
EncodeThread();
public slots:
void encode();
signals:
void encodeProgress(int i);
void finished();
private:
QThread myThread;
};
EncodeThread::EncodeThread() {
moveToThread(&myThread);
myThread.start();
}
void EncodeThread::encode()
{
printf("EncodeThread::encode() on thread %u\n", (unsigned int) QThread::currentThreadId());
for (int i = 0; i < 6; ++i) {
// encode for 1 second or so
printf("EncodeThread::encode() working on thread %u\n", (unsigned int) QThread::currentThreadId());
Sleeper::sleep(1);
emit encodeProgress(i);
}
emit finished();
printf("EncodeThread::encode() - done\n");
}
// a controller to manage and monitor an EncoderThread instance
class VideoEncoderController : public QObject
{
Q_OBJECT
public:
void start();
public slots:
void setValue(int);
void encodingDone();
signals:
void encodingBegin();
};
void VideoEncoderController::start()
{
printf("VideoEncoderController::start() on thread %u\n", (unsigned int) QThread::currentThreadId());
emit encodingBegin();
}
void VideoEncoderController::setValue(int x)
{
printf("VideoEncoderController::setValue(int %d) on thread %u\n", x, (unsigned int) QThread::currentThreadId());
}
void VideoEncoderController::encodingDone()
{
printf("VideoEncoderController::encodingDone() on thread %u\n", (unsigned int) QThread::currentThreadId());
}
// a demo program that wires up a VideoEncoderController object to
// an EncoderThread
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
EncodeThread encThread;
VideoEncoderController controller;
QObject::connect(&encThread, SIGNAL(encodeProgress(int)), &controller, SLOT(setValue(int)));
QObject::connect(&encThread, SIGNAL(finished()), &controller, SLOT(encodingDone()));
QObject::connect(&controller, SIGNAL(encodingBegin()), &encThread, SLOT(encode()));
printf("hello world on thread %u\n", (unsigned int) QThread::currentThreadId ());
controller.start();
return a.exec();
}
#include "main.moc"
You must derive QThread, not QObject. run() method is an abstract method of QThread.
For future programmers I'm adding this answer. There are generally 3 approaches to multi-threading in Qt. Low Level, Reusing(lets say Mid Level) and High Level.
Low level also includes two different approaches. In Low level you can Inherit QThread class and provide the code that you want to run in parallel inside void QThread::run() override;. After calling QThread::start() on your drived class, code in run will execute.
Another approach in Low Level Multi-threading in Qt is relaying on Qt's event loops. In this way you create a class that is drived from QObject, not necessarily from QThread and then move that class to a new QThread with this. And after that you will call start() on that QThread object(this QThread object is an object of type QThread . You don't have to subclass QThread here. Just instantiate one object. It is where I believe you misunderstood in your code).
After calling start() on your QThread object, its event loop starts in another thread and signals from anywhere in your code that are connected to your QObject drived class's slots will run in that event loop in parallel as long as you don't use Qt::DirectConnection as last argument to this.
These two approaches has their own benefits and drawbacks. When sub-classing QThread and using Qthread::run(), if your code inside run is running inside a while(true) loop, one of your processor's threads will always be occupied with Qthread::run() code and not in the threadpool for other threads in your program.
The QObject::moveToThread() approach is useful for most cases. But if the QObject drived classe's slot is going to be called very frequently, like 100 or 1000 times per second, memory usage rises, due to possible arguments passed to the slot, and some of this signals may never reach the slot.
I am new to QT and I am doing some learning.
I would like to trigger a slot that modify a GUI widget from a C++ thread(Currently a Qthread).
Unfortunatly I get a: ASSERTION failed at: Q_ASSERT(qApp && qApp->thread() == QThread::currentThread());
here is some code:
(MAIN + Thread class)
class mythread : public QThread
{
public:
mythread(mywindow* win){this->w = win;};
mywindow* w;
void run()
{
w->ui.textEdit->append("Hello"); //<--ASSERT FAIL
//I have also try to call a slots within mywindow which also fail.
};
};
int main(int argc, char *argv[])
{
QApplication* a = new QApplication(argc, argv);
mywindow* w = new mywindow();
w->show();
mythread* thr = new mythread(w);
thr->start();
return a->exec();
}
Window:
class mywindow : public QMainWindow
{
Q_OBJECT
public:
mywindow (QWidget *parent = 0, Qt::WFlags flags = 0);
~mywindow ();
Ui::mywindow ui;
private:
public slots:
void newLog(QString &log);
};
So I am curious on how to update the gui part by code in a different thread.
Thanks for helping
stribika got it almost right:
QMetaObject::invokeMethod( textEdit, "append", Qt::QueuedConnection,
Q_ARG( QString, myString ) );
cjhuitt's right, though: You usually want to declare a signal on the thread and connect it to the append() slot, to get object lifetime management for free (well, for the price of a minor interface change). On a sidenote, the additional argument:
Qt::QueuedConnection ); // <-- This option is important!
from cjhuitt's answer isn't necessary anymore (it was, in Qt <= 4.1), since connect() defaults to Qt::AutoConnection which now (Qt >= 4.2) does the right thing and switches between queued and direct connection mode based on QThread::currentThread() and the thread affinity of the receiver QObject at emit time (instead of sender and receiver affinity at connect time).
In addition to stribika's answer, I often find it easier to use a signal/slot connection. You can specify that it should be a queued connection when you connect it, to avoid problems with the thread's signals being in the context of its owning object.
class mythread : public QThread
{
signals:
void appendText( QString );
public:
mythread(mywindow* win){this->w = win;};
mywindow* w;
void run()
{
emit ( appendText( "Hello" ) );
};
};
int main(int argc, char *argv[])
{
QApplication* a = new QApplication(argc, argv);
mywindow* w = new mywindow();
w->show();
mythread* thr = new mythread(w);
(void)connect( thr, SIGNAL( appendText( QString ) ),
w->ui.textEdit, SLOT( append( QString ) ),
Qt::QueuedConnection ); // <-- This option is important!
thr->start();
return a->exec();
}
You need to use QMetaObject::invokeMethod. For example:
void MyThread::run() {
QMetaObject::invokeMethod(label, SLOT(setText(const QString &)), Q_ARG(QString, "Hello"));
}
(The above code comes from here: http://www.qtforum.org/article/26801/qt4-threads-and-widgets.html)
I don't think you are allowed to call directly things that results in paint events from any
other threads than the main thread. That will result in a crash.
I think you can use the event loop to call things asynchronously so that the main gui thread picks up and then does the updating from the main thread, which is what cjhuitt suggests.