QT + How to call slot from custom C++ code running in a different thread - qt

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.

Related

How can I connect a signal to QWidget::update slot?

I am using Qt5 with new signal/slot syntax.
I don't know why the following code doesn't work:
QWidget *widget = new QWidget();
connect(pipeline, &Pipeline::NewFrame, widget, &QWidget::update);
I get the error:
no matching member function for call to 'connect' why?
Pipeline class inherits from QObject and NewFrame signal has the same signature as QWidget::update
class Pipeline
: public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Pipeline)
public:
Pipeline(QObject *parent);
signals:
void NewFrame();
};
I am using QtCreator on Arch Linux with g++.
TL;DR: The pipeline should be signaling an image, and the widget should have a SetImage method:
class Pipeline : public QObject {
Q_OBJECT // important
public:
Q_SIGNAL void NewFrame(const QImage &);
...
};
class Viewer : public QWidget {
Q_OBJECT // important
QImage m_image;
public:
Q_SLOT void SetImage(const QImage &image) {
m_image = image;
update();
}
...
};
This is how you'd be using it - note that Viewer knows nothing about Pipeline, because it shouldn't: it just shows new frames, wherever they come from.
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Pipeline pipeline;
Viewer viewer;
QObject::connect(&pipeline, &Pipeline::NewFrame, &viewer, &Viewer::SetImage);
return app.exec();
}
Connecting anything to QWidget::update directly, especially from external sources, is usually a sign of bad design.
To satisfy your curiosity, you can use a lambda or qOverload to specify what you're connecting to, to fix the very error you're seeing - caused by ambiguity of the the type of the method pointer. Any of the following will work:
connect(…, widget, qOverload<>(&QWidget::update));
or
auto constexpr update = qOverload<>(&QWidget::update));
connect(…, widget, update);
or
connect(…, widget, [widget]{ widget->update(); });

How to prevent the QBasicTimer::stop: Failed warning when objects become threadless?

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();
}

Qpush Button -> click signal from QPushButton failed to fire up function in slot

i Guys ,
Qt Version 5.1
I am working on existing qt project and I failed to understand why when I click on button , it fails to fire up function in slot
What I am trying to do is my Qt application connects to the network and displays all the machine with their mac address using QTreewidget. This part works fine
my nest task is to select the mac-adrress from the QTree object created in above step AND then create a pushbutton to start the upgrade process on that machine.
Below is my source code
1) main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Regular_Work w;
w.show();
return a.exec();
}
2) regular_work.cpp
Regular_Work::Regular_Work(QWidget *parent)
: QMainWindow(parent),macAdd_tree_p_( 0 ), reg_upgrade_button_(0),
box_table_p_( 0 ),
udp_listner_p_( 0 )
{
ui.setupUi(this);
// Create the main view
create_main_view( this, macAdd_tree_p_, box_table_p_ , reg_upgrade_button_);
init(); // this function upgradels other signals and slots from other class to find the network and upgradel the slots which displays teh tree view of mac address connected to a network.
create_menu_actions();
}
Regular_Work::~Regular_Work()
{
}
// this function is called from another slot when itemClicked signal is received from QTreeWidgetItem
void Regular_Work::set_reg_upgrade_button_visible( Regular_Work* main_p )
{
QPushButton* reg_upgrade_button = new QPushButton ("Regular_upgradei");
reg_upgrade_button->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ;
QWidget* centralWidget = new QWidget( main_p );
centralWidget->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
QHBoxLayout* layout = new QHBoxLayout(centralWidget);
layout->addWidget( reg_upgrade_button_ );
main_p->setCentralWidget(centralWidget);
reg_upgrade_button->setVisible( true );
connect(reg_upgrade_button, SIGNAL( clicked() ), main_p, SLOT( start_Work( "start Work" ) ) ); // this is teh problem ?
}
void Regular_Calibration::start_Work( const QString& error_message )
{
QMessageBox::information( this,
tr( "Push button works " ),
error_message );
}
Thanks a lot for the help
Your problem lies in the fact that you're trying to pass a parameter value in the connect statement. This can not work: -
SLOT( start_Work( "start Work" ) )
What you need to do is to create a slot that matches the arguments of the clicked() signal. Then in that slot function, you can call your start_Work("start Work") function. Something like this: -
class Regular_Work : public QMainWindow
{
Q_OBJECT
private:
void start_Work(const QString&);
private slots:
void ReceiveButtonClicked();
};
void RegularWork::ReceivedButtonClicked()
{
start_Work("start Work");
}
Connect the signal and slots: -
connect(reg_upgrade_button, SIGNAL( clicked() ), main_p, SLOT( ReceiveButtonClicked()));
If you use Qt 5, you can use the new connection syntax: -
connect(reg_upgrade_button, &QPushButton::clicked, main_p, &RegularWork::ReceiveButtonClicked);
This has the advantage of telling you if there's a problem at compile time, as well as taking pointers to functions, so you don't specify any arguments for the functions.

qt5: how to create and display custom qdialog from static function within a qthread

Let's say that you've created a new thread that then calls a static function after it has been started. Within that static function you need to create and display a custom qdialog. How can you create it so that it has no parent and is located in the proper thread?
The constructor sets the parent to 0 but it still reports an error about being unable to create children for a parent in a different thread. Since it's a static function I can't use the "this" object and without "this" I can't retrieve the current thread or thread id. I thought I might be able to call myCustomDialog->moveToThread() but I have no idea how to determine the correct thread from a static function.
If I use one of the QMessageBox static functions everything works fine. For example, calling QMessageBox::information(0, tr("Title"), tr("Message")) doesn't report any errors. How can I code my custom qdialog to function similar to the qmessagebox static function?
Is there any way to retrieve a list of all running threads from the qApp object? Any other suggestions?
static int myFunction();
int myObject::myFunction()
{
myCustomDialog *mcd = new myCustomDialog();
// as soon as I call exec() it reports an error and crashes
mcd->exec();
// QObject: Cannot create children for a parent that is in a different thread.
// can't call mcd->moveToThread() without knowing the current thread
// how can I determine the current thread from this static function?
// if parent = 0 then why is this error occurring?
return 0;
}
myCustomDialog(QWidget *parent = 0);
myCustomDialog::myCustomDialog(QWidget *parent) : QDialog(parent)
{
// create widgets and layout here
}
Don't. Creating QWidget objects from another thread is a bad idea. The Documentation states:
In GUI applications, the main thread is also called the GUI thread
because it's the only thread that is allowed to perform GUI-related
operations.
The way I normally get around this is to emit a signal from my object in the non-GUI thread that's connected to an object living in the main thread (often MainWindow for me). The receiving object then creates the dialog on the main thread.
As mentioned in the other answer, this connection can block your worker thread if needed by establishing the connection type as Qt::BlockingQueuedConnection.
For more information on invoking functions from other threads, see this post.
Sample... You may adapt it to make calls from static functions, but I don't think that it is necesary. It is good practice to work with threads in next way: You should create your dialog in GUI thread and connect it's exec() slot to your signal with Qt::BlockingQueuedConnection
Worker.h
#include <QObject>
class Worker
: public QObject
{
Q_OBJECT
signals:
void showDialog();
public:
Worker( QObject *parent = NULL );
~Worker();
public slots:
void doLongWork();
private:
};
Worker.cpp
#include <QThread>
#include <QMessageBox>
#include <QDebug>
#include <QCoreApplication>
#include <Windows.h>
Worker::Worker( QObject *parent )
: QObject( parent )
{
}
Worker::~Worker()
{
}
void Worker::doLongWork() // You may override QThread::run with same effect, but it is bad practice
{
qDebug() << "Worker thread id = " << QThread::currentThreadId();
::MessageBoxA( NULL, "Click to show dialog in 3 seconds", NULL, 0 );
::Sleep( 3000 );
emit showDialog(); // "Showing" dialog from non-GUI thread. And wait for close
::MessageBoxA( NULL, "Dialog closed!", NULL, 0 );
qApp->quit();
}
main.cpp
#include <QApplication>
#include <QDialog>
#include <QThread>
#include <QDebug>
#include "Worker.h"
int main(int argc, char *argv[])
{
QApplication a( argc, argv );
a.setQuitOnLastWindowClosed( false );
QDialog dlg;
QThread workerThread;
Worker worker;
qDebug() << "Main thread id = " << QThread::currentThreadId();
QObject::connect( &workerThread, SIGNAL( started() ), &worker, SLOT( doLongWork() ) );
QObject::connect( &worker, SIGNAL( showDialog() ), &dlg, SLOT( exec() ), Qt::BlockingQueuedConnection ); // !!!See connection type!!!
worker.moveToThread( &workerThread );
workerThread.start();
return a.exec();
}
Note: WinAPI MessageBoxes are used only to visualize that thread is really waiting for close of dialog.

Scientific Visualization with OpenGL and Qt

I am trying to write an OpenGL visualization program for some scientific data using Qt. I would like to be able to use my existing program unchanged and simply be able to call the glwidget and tell it to update the data at the end of each time step. However in order to run a Qt program it appears you have to use QApplication and then qt.run() which blocks the cpu.
Here is the pseudo code
main()
{
..set up stuff
myVisualizer = new myGLWidget();
for(int i=0;i<1000;i++)
{
..do calculations
myVisualizer.update(new data)
}
}
I realize that I could put all of my existing code in to a QThread and have it send a signal whenever it is done to connect to an update. It would just be easier this way. Does anybody have an idea how to solve this?
If you really don't want to investigate the threaded solution, which would be nicer all around, you can use the special-case timeout with 0. Basically, when you run a timer with a timeout of 0, it runs the appropriate code after processing the events that are currently on the event queue. So, you could set up something like this:
class MyDialog : public QDialog
{
Q_OBJECT
public:
MyDialog()
{
m_step = 0;
QTimer::singleShot( 0, this, SLOT( Process() ) );
}
public slots:
void Process()
{
// do calculations
m_step++;
QTimer::singleShot( 0, this, SLOT( Redraw() ) );
if ( m_step != 1000 )
QTimer::singleShot( 0, this, SLOT( Process() ) );
}
void Redraw() { // do redrawing code here }
private:
int m_steps;
};
And then combine it with the Qt-proper main code:
int main( int argc, char** argv )
{
QApplication app( argc, argv );
MyDialog dialog;
dialog.show();
return ( app.exec() );
}
You can use QThread in your application and do the calculations in a seperate thread.
What you have to do is to subclass the QThread and implement the run() method.
You can create a calculator class and add some signals in that class and connect the signal to your display widget's update slot (in this case QGLWidget::updateGL()).
Here is a rough example: (All you have to is to create a thread and DisplayWidget in your main() function and set the thread's DisplayWidget.)
class Calculator: public QObject
{
Q_OBJECT
public:
Calculator();
void start();
signals:
void updateDisplayWidget(/* you can put the resulting data */);
};
class DisplayWidget(): public QGLWidget
{
Q_OBJECT
// override paint methods here
public slots:
void slotUpdateDisplayWidget(/* you can receive the resulting data*/);
};
class MyThread : public QThread
{
public:
void run();
void setDisplayWidget(DisplayWidget* displayWidget);
private:
Calculator mCalculator;
};
void MyThread::run()
{
mCalculator.start();
exec();
}
MyThread::setDisplayWidget(DisplayWidget* displayWidget)
{
displayWidget->moveToThread(this);
connect(&mCalculator, SIGNAL(updateDisplayWidget()), displayWidget, SLOT(slotUpdateDisplayWidget()));
}

Resources