I am trying to update gui from another thread by using this: https://stackoverflow.com/a/14546167/2236297
This is my workerthread:
class WorkerThread : public QThread {
void run() {
while(1) {
//QTcpSocket messenger;
//messenger.connectToHost("192.168.1.20", 61000);
//if(!messenger.waitForConnected(3000))
//{
emit progressChanged("111");
//}
}
}
// Define signal:
signals:
void progressChanged(QString q)
{
}
};
Only difference is I declared this class as a inner class and defined progressChanged. In his example signal was just declared, not defined.
My onProgressChanged:
void ApplicationController::onProgressChanged(QString info)
{
// Processing code
ui.label_2->setText("Latest info: " + info);
}
This is how I start thread in my constructor:
ApplicationController::ApplicationController(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
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
}
Question is: why my slot isn't called. What should I change?
EDIT
Changed workerthread.
.h file
class WorkerThread : public QThread
{
Q_OBJECT
public:
WorkerThread();
~WorkerThread();
void run();
private:
signals:
void progressChanged(QString info);
};
.cpp file
WorkerThread::WorkerThread() { }
WorkerThread::~WorkerThread() { }
void WorkerThread::run()
{
while(1) {
QTcpSocket messenger;
messenger.connectToHost("192.168.1.20", 61000);
if(!messenger.waitForConnected(3000))
{
emit progressChanged((QString("%1").arg(messenger.error())));
}
}
}
In debug, emit works. But slot is not called in main function.
SOLVED
There are multiple errors:
First of all workerThread should be defined as seperate class not an inner class.
Slot should be declared under slots:
public slots:
void onProgressChanged(QString info);
Related
I'd like to insert the serial port in a separate QThread, but the application crashes. I wrote the following C++ classes
Worker.h
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0);
signals:
void finished();
void error(QString err);
public slots:
void process();
};
class WorkerInterface : public QObject
{
Q_OBJECT
public:
explicit WorkerInterface(QObject *parent = nullptr);
~WorkerInterface();
serialport *readSerialPort();
signals:
void threadStoppedChanged();
public slots:
void errorString(QString errorMsg);
void stopThread();
private:
QThread m_thread;
serialPort *m_serial;
};
Worker::Worker(QObject *parent)
: QObject(parent)
{
}
void Worker::process()
{
emit finished();
}
Worker.cpp
WorkerInterface::WorkerInterface(QObject *parent)
: QObject(parent)
, m_thread(this)
{
serialPort::serialPortMaster = new serialPort(nullptr);
m_serial = serialPort::serialPortMaster;
serialPort::serialPortMaster->moveToThread(&m_thread);
connect(&m_thread, SIGNAL(started()),serialPort::serialPortMaster, SLOT(Init()));
m_thread.start();
}
WorkerInterface::~WorkerInterface()
{
m_thread.quit();
m_thread.wait(1000);
if (!m_thread.isFinished())
m_thread.terminate();
}
void WorkerInterface::errorString(QString errorMsg)
{
qDebug() << "error" << errorMsg;
}
void WorkerInterface::stopThread()
{
m_thread.quit();
m_thread.wait(1000);
if (!m_thread.isFinished())
m_thread.terminate();
emit threadStoppedChanged();
}
serialPort* WorkerInterface::readSerialPort()
{
return(m_serialPort);
}
In the main.cpp I wrote the following code:
WorkerInterface workerInterface;
engine.rootContext()->setContextProperty("newserial", workerInterface.readSerialPort());
QQmlComponent component(&engine,QUrl(QStringLiteral("qrc:/Pages/Content/Qml/main.qml")));
QObject *qmlObject = component.create();
When the code arrives at the last instruction in main.cpp, the application crashes and in the QT creator console there is the following messages:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QSerialPort(0xee18c0), parent's thread is QThread(0xc8d8b0), current thread is QThread(0x7fffffffdc60)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QSerialPort(0xee18c0), parent's thread is QThread(0xc8d8b0), current thread is QThread(0x7fffffffdc60)
QQmlEngine: Illegal attempt to connect to serialPort(0xee1710) that is in a different thread than the QML engine QQmlApplicationEngine(0x7fffffffdc30.
Could someone help me to solve the crash?
Many thanks in advance.
Assuming that you have device which responds with text, the best and simplest way to do it is something like this:
class IODevLineReader
{
Q_OBJECT
public:
explicit IODevLineReader(QObject *parent);
public signals:
void lineWasReceived(const QString &line);
public slots:
void onReadyRead() {
QIODevice *dev = qobject_cast<QIODevice *>(sender());
while (dev && dev->canReadLine()) {
auto lineBytes = dev->readLine();
emit lineWasReceived(lineBytes);
}
}
};
Just connect QSerialPort::readyRead() to IODevLineReader::onReadyRead() and connect some slot to IODevLineReader::lineWasReceived() signal and you are done without use of threads.
And if you still insist to use thread, just use same object tree and move it to specified thread.
I want to pass a QString to a thread.Using this answer,
Here is my code:
in MainWindow.cpp:
mmthread = new mythread;
mmthread->start();
connect(this,SIGNAL(sendtothread(QString)),mmthread,SLOT(getfrom_main(QString)),Qt::QueuedConnection);
emit sendtothread(mystr);
in mainwindow.h:
signals:
void sendtothread(QString);
in mythread.cpp:
void mythread::getfrom_main(QString str)
{
//something
}
in mythread.h:
public slots:
void getfrom_main(QString);
But it seems getfrom_main is not called at all.
Where is my mistake?
EDIT:
I have 3 similar threads like this:
in mythread.cpp:
mythread :: mythread()
{
moveToThread(this);
}
void mythread::run(){
//something1
}
void mythread::getfrom_main(QString comm)
{
comment = comm;
emit message(comment);
}
in mythread.h:
class mythread : public QThread
{
Q_OBJECT
public:
explicit mythread();
void run();
signals:
void message (QString);
private:
QString comment;
public slots:
void getfrom_main(QString);
};
something1 always executes in all my threads.but not about getfrom_main.Thanks.
Wrong:
mythread :: mythread()
{
moveToThread(this); // you don't need to do it
}
Wrong (you really don't need to inherit QThread in your code):
void mythread::run()
{
//something1
// after "something" you need to run an event loop:
exec();
}
exec() will run an event loop that will process all your signals and slots.
I sticked to the tutorial about threaded qt-networking (which is here: http://doc.qt.io/qt-5/qtnetwork-threadedfortuneserver-example.html), I made some minor changes and integrated it into my main program. However incomingConnection() never gets executed, on the other hand the client is able to connect. Since I'd like to work with incomingConnection() it became obsolete to work with the SIGNAL(newConnection()) but even this isn't working.
Somebody knows what's going wrong?
Here my .h
#include <QtNetwork>
#include <QTcpServer>
#include <QTcpSocket>
#include <QThread>
class WirelessNetThread: public Thread
{
Q_OBJECT
public:
WirelessNetThread(int socketDescriptor, QObject * parent);
void run() Q_DECL_OVERRIDE;
signals:
void error(QTcpSocket::SocketError socketError);
private:
int socketDescriptor;
QString text;
};
class WirelessNet : public QTcpServer
{
Q_OBJECT
public:
WirelessNet(QObject *parent = 0);
protected:
void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;
};
And the .cpp
WirelessNetThread::WirelessNetThread(int socketDescriptor, QObject *parent):QThread(parent), socketDescriptor(socketDescriptor)
{
}
void WirelessNetThread::run()
{
QTcpSocket tcpSocket;
if ( !tcpSocket.setSocketDescriptor(socketDescriptor))
{
emit error(tcpSocket.error());
return;
}
tcpSocket.disconnectFromHost();
tcpSocket.waitForDisconnected();
}
WirelessNet::WirelessNet(QObject *parent): QTcpServer(0)
{
listen(QHostAddress::Any, 5220);
printf("is listening %d\n", this->isListening());
}
void WirelessNet::incomingConnection(qintptr socketDescriptor)
{
qDebug() << "incomming \n";
printf("incomming \n");
WirelessNetThread *thread = new WirelessNetThread(socketDescriptor, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
here the excerpt out of my main program, where it is initiated (by the way it doesn't matter if I leave out moveToThread():
WirelessNet *wifi = new WirelessNet(this->parent());
wifi->moveToThread(this->thread());
Even this has no influence if I add these lines after the initalization of wifi:
wifi = new WirelessNet(this->parent());
QEventLoop testLoop;
testLoop.exec();
In other words "incomming" is never printed out, and so I'm not able to work on. Has anyone an idea, this is pretty much 1:1 the code from the tutorial that's what confuses me.
In your main code:
WirelessNet *wifi = new WirelessNet(0); // 0 = assign no parent
QThread *wifiThread = new QThread;
wifi->moveToThread(wifiThread);
QObject::connect(wifiThread, SIGNAL(started()), wifi, SLOT(startWifi()));
// start() will start its own event loop, it will emit started(), therefore startWifi() slot will be called.
wifiThread->start();
Then your WirelessNet class header:
class WirelessNet : public QTcpServer
{
Q_OBJECT
public:
WirelessNet(QObject *parent = 0);
protected:
void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;
public slots:
void startWifi();
};
Then your WirelessNet class body:
WirelessNet::WirelessNet(QObject *parent) :
QTcpServer(parent)
{
// Do nothing much here because we want to initialise new stuff in our thread.
// When this function runs we have not moved this to the new thread - or even started it.
}
void WirelessNet::incomingConnection(qintptr socketDescriptor)
{
qDebug() << "incomming \n";
printf("incomming \n");
WirelessNetThread *thread = new WirelessNetThread(socketDescriptor, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
// Called when the thread has started
void WirelessNet::startWifi()
{
// Anything done here is now safely within out new thread.
listen(QHostAddress::Any, 5220);
printf("is listening %d\n", this->isListening());
}
note this is example code, I wrote it directly into stack overflow it has not been compiled, so there are probably some errors :) There are some key points, that I have commented, where you may have gone wrong in your original attempt.
I have a problem with signal/slots in a QThread class. My design looks like this:
class Manager : public QObject {
Q_OBJECT
public:
Manager(QObject* parent) : QObject(parent) {
Thread thread* = new Thread(this);
connect(this, SIGNAL(testsignal()), thread, SLOT(test()));
thread->start();
...
emit testsignal();
}
signals:
void testsignal();
};
class Thread : public QThread {
Q_OBJECT
public slots:
void test() {
qDebug() << "TEST";
}
private:
void run() {}
};
The signal never reaches my test() method. Can someone help? Thanks.
The problem is that sending signals across threads results in queuing the signal into the target thread's event queue (a queued connection). If that thread never processes events, it'll never get the signal.
Also, according to the QThread::run documentation:
Returning from this method will end the execution of the thread.
In other words, having an empty run method results in instant termination of the thread, so you're sending a signal to a dead thread.
Signals sent to a QThread object will go to the thread of the parent object. In this case to the same thread that created it.
To have a object live on another thread you should move it to that thread:
class Manager : public QObject {
Q_OBJECT
public:
Manager(QObject* parent) : QObject(parent) {
Thread thread* = new QThread(this);
Receiver* rec = new Receiver(); //no parent
connect(this, SIGNAL(testsignal()), rec, SLOT(test()));
connect(thread, SIGNAL(finished()), rec, SLOT(deleteLater()));
rec->moveToThread(thread);
thread->start();
...
emit testsignal();
}
signals:
void testsignal();
};
class Receiver: public QObject {
Q_OBJECT
public slots:
void test() {
qDebug() << "TEST";
}
};
I know how to wait for a single object to finish, using
QEventLoop eventLoop;
connect(&obj, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec();
But now I have several objects which I want to 'run' in parallel, so I need to wait until all of them have sent their finished() SIGNALs.
This would be like a signals-and-slots version of the WaitForMultipleObjects WinApi function.
How should I go about doing that?
I would connect the finished signal to a class that counts the # of signals received and emits quit() when it hits the expected count.
Something like this:
class EmitIfCountReached : public QObject
{
Q_OBJECT
public:
EmitIfCountReached( int expectedCount, QObject* parent = nullptr) : m_expected(expectedCount), m_count(0), QObject(parent) {}
signals:
void finished();
protected slots:
void increment() {
m_count++;
if (m_count >= m_expected) {
emit finished();
}
}
protected:
int m_count;
int m_expected;
};