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.
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've got a c++ code including GUI, in which I need to run a time consuming loop for optimization.
class OptimizationAlgorith(data *data);
{
private:
var var1;
var var2;
public:
method1();
method2();
..
timeConsumingMethod(data);
}
this need to be called in a GUI class like following:
class QRegistration: public QWidget
{
Q_OBJECT
private:
data *m_data;
QPushButton *m_button_run;
OptimizationAlgorithm *m_optimizationalgorithm;
WorkerThread *m_workerThread;
QThread *m_thread;
..
private slots:
void on_pushButton_run_clicked();
void registrationDone();
I need to move the timeConsumingMethod into a seperate thread than main thread, so that the GUI does not freez while timeConsumingMethodis running.
I have made a new class "WorkerThread" using the official documentation of Qt, which looks like:
class WorkerThread : public QObject
{
Q_OBJECT
public:
WorkerThread(ApplicationData* data, QOptimizationAlgorithm * OptimizationAlgorithm);
~WorkerThread();
public slots:
void run(data* data);
signals:
void finished();
private slots:
private:
OptimizationAlgorithm *m_OptimizationAlgorithm;
ApplicationData *m_data;
}
How shoud I now implement my run()in WorkerThread? Can I simply write:
void WorkerThread::run(data *m_data)
{
m_optimization.timeConsumingMethod(m_data);
emit finished();
}
or do I have to copy the whole definition of timeConsumingMethod in run()? Why/Why not?
You don't need to do any explicit thread management, Qt already does it for you. Use QtConcurrent::run to do the work in a worker thread from the thread pool.
You should also decouple the controller that manages the work, and the UI. The knowledge of how to couple these objects should be separate from the objects themselves. This allows more flexibility in the design of the UI and the controller, and helps avoid several classes of errors that stem from accessing non-thread-safe methods from incorrect threads.
Complete example:
// https://github.com/KubaO/stackoverflown/tree/master/questions/threadwork-simple-40865259
#include <QtWidgets>
#include <QtConcurrent>
struct ApplicationData {};
struct OptimizationAlgorithm {
void timeConsumingMethod(QSharedPointer<ApplicationData>) {
QThread::sleep(3);
}
};
class Controller : public QObject {
Q_OBJECT
QSharedPointer<ApplicationData> m_data{new ApplicationData};
OptimizationAlgorithm m_algorithm;
public:
Q_SLOT void run() {
QtConcurrent::run([this]{
emit busy();
m_algorithm.timeConsumingMethod(m_data);
emit finished();
});
}
Q_SIGNAL void busy();
Q_SIGNAL void finished();
};
class Registration : public QWidget {
Q_OBJECT
QVBoxLayout m_layout{this};
QLabel m_status{"Idle"};
QPushButton m_run{"Run"};
public:
Registration() {
m_layout.addWidget(&m_status);
m_layout.addWidget(&m_run);
connect(&m_run, &QPushButton::clicked, this, &Registration::reqRun);
}
Q_SIGNAL void reqRun();
Q_SLOT void onBusy() { m_status.setText("Running"); }
Q_SLOT void onFinished() { m_status.setText("Idle"); }
};
void setup(Registration *reg, Controller *ctl) {
using Q = QObject;
Q::connect(reg, &Registration::reqRun, ctl, &Controller::run);
Q::connect(ctl, &Controller::busy, reg, &Registration::onBusy);
Q::connect(ctl, &Controller::finished, reg, &Registration::onFinished);
}
int main(int argc, char ** argv) {
QApplication app{argc, argv};
Controller ctl;
Registration reg;
setup(®, &ctl);
reg.show();
return app.exec();
}
#include "main.moc"
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);
I am a beginner of qt.I adopted the way recommended by QThread Class in qt documentation.
The method used in documentation is as follows.
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
So I have Class SocketThreadCtrler and Class SocketWorker respectively.
Concrete code is as follows.
socketthreadctrler.h is as follows.
#ifndef SOCKETTHREADCTRLER_H
#define SOCKETTHREADCTRLER_H
#include <QObject>
#include <QThread>
#include "socketworker.h"
class SocketThreadCtrler : public QObject
{
Q_OBJECT
private:
QThread workThread;
public:
explicit SocketThreadCtrler(QObject *parent = 0);
~SocketThreadCtrler();
private:
void connSigAngSlots();
public slots:
void login(QString acnt, QString passwd);
void EmitSigCheckLogin(bool loginStatus);
signals:
void SIG_CONECTSERVER();
void SIG_WRITEMSG(QByteArray&);
void SIG_CHECKLOGIN(bool);
private:
SocketWorker* worker;
// MainUI* mainUI;
};
#endif // SOCKETTHREADCTRLER_H
socketThreadCtrler.cpp
#include "header/backend/communication/socketthreadctrler.h"
#include "header/backend/communication/smessage1.h"
SocketThreadCtrler::SocketThreadCtrler(QObject *parent) : QObject(parent)//, worker(NULL)
{
// SocketWorker* worker = new SocketWorker();
worker=new SocketWorker;
worker->moveToThread(&workThread);
connSigAngSlots();
workThread.start();
emit SIG_CONECTSERVER();
}
SocketThreadCtrler::~SocketThreadCtrler()
{
workThread.quit();
workThread.wait();
}
void SocketThreadCtrler::connSigAngSlots()
{
connect(&workThread,SIGNAL(finished()),worker,SLOT(deleteLater()));
connect(this,SIGNAL(SIG_CONECTSERVER()),worker,SLOT(connectServer()),Qt::QueuedConnection);
connect(this,SIGNAL(SIG_WRITEMSG(QByteArray&)),worker,SLOT(writeMsg(QByteArray&)));
connect(worker,SIGNAL(Sig_LoginStatus(bool)),this,SLOT(EmitSigCheckLogin(bool)));
}
void SocketThreadCtrler::login(QString acnt, QString passwd)
{
//如何给login专门开一个线程
SMessage1 msg1(acnt, passwd);
emit SIG_WRITEMSG(msg1.getMsg());
}
void SocketThreadCtrler::EmitSigCheckLogin(bool loginStatus)
{
emit SIG_CHECKLOGIN(loginStatus);
}
socketWorker.h
#ifndef SOCKETWORKER_H
#define SOCKETWORKER_H
#include <QObject>
#include <QTcpSocket>
#include "messagefactory.h"
#include "rmessage.h"
#include "message.h"
#include "auxfuncset.h"
#include "smessage.h"
class SocketWorker : public QObject
{
Q_OBJECT
private:
static const quint16 serverPort=12345;
static const QString serverAddr;
QTcpSocket sock;
public:
explicit SocketWorker(QObject *parent = 0);
void WorkerEmitSigLogin(bool loginStatus);
private:
bool isServerMsg();
quint32 getMsgLen();
void getMsg(quint32 msgLen, QByteArray& msgBytes);
signals:
void Sig_LoginStatus(bool loginStatus);
public slots:
void connectServer();
void writeMsg(QByteArray&Msg);
void procMsg();
//private:
};
#endif // SOCKETWORKER_H
socketWorker.cpp
#include "header/backend/communication/socketworker.h"
const QString SocketWorker::serverAddr("127.0.0.1");
SocketWorker::SocketWorker(QObject *parent) : QObject(parent)
{
}
void SocketWorker::connectServer()
{
QString tmp=serverAddr;
sock.connectToHost(tmp,serverPort);
connect(&sock,SIGNAL(readyRead()) ,this, SLOT(procMsg()));
}
void SocketWorker::writeMsg(QByteArray& Msg)
{
sock.write(Msg);
// QAbstractSocket will start sending data automatically
// once control goes back to the event loop
sock.flush();
}
void SocketWorker::procMsg()
{
if(!isServerMsg()) return;
quint32 msgLen=0;
msgLen=getMsgLen();
if(0 == msgLen) return;
QByteArray msgBytes;
getMsg(msgLen,msgBytes);
RMessage* msg = MessageFactory::createMessage(msgBytes);
msg->process(this);
delete msg;
}
bool SocketWorker::isServerMsg()
{
//MSGHEADER
quint32 msgHead=0;
while(AuxFuncSet::readQuint32(&sock, msgHead))
{
if(msgHead == Message::MSGHEADER)
{
return true;
}
}
return false;
}
quint32 SocketWorker::getMsgLen()
{
while(sock.bytesAvailable()<sizeof(quint32));
quint32 msgLen=0;
AuxFuncSet::readQuint32(&sock,msgLen);
return msgLen;
}
void SocketWorker::getMsg(quint32 msgLen, QByteArray& msgBytes)
{
while(sock.bytesAvailable()<msgLen);
msgBytes = sock.read(msgLen);
}
void SocketWorker::WorkerEmitSigLogin(bool loginStatus)
{
emit Sig_LoginStatus(loginStatus);
}
The error message provided by compiler is
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0xb988c8), parent's thread is QThread(0xb93528), current thread is QThread(0x8dfe2c)
From my debugging, I find the key section is signal-slot connect part that causes this problem.
Specifically,there are four connection statements.
i.e.,
connect(&workThread,SIGNAL(finished()),worker,SLOT(deleteLater()));
connect(this,SIGNAL(SIG_CONECTSERVER()),worker,SLOT(connectServer()),Qt::QueuedConnection);
connect(this,SIGNAL(SIG_WRITEMSG(QByteArray&)),worker,SLOT(writeMsg(QByteArray&)));
connect(worker,SIGNAL(Sig_LoginStatus(bool)),this,SLOT(EmitSigCheckLogin(bool)));
But only the middle two statements causes this error.Concretely,if I delete the middle two statements,i.e.,
connect(this,SIGNAL(SIG_CONECTSERVER()),worker,SLOT(connectServer()),Qt::QueuedConnection);
connect(this,SIGNAL(SIG_WRITEMSG(QByteArray&)),worker,SLOT(writeMsg(QByteArray&)));
then there are no errors.
So I am confused.After one and a half hour,I still don't find a effective solution and a reasonable explanation.So I think I need help.Thanks in advance.
I am trying to implement Signal and Slot system between the main gui and another object moved to another thread...the following is how the class design looks like...unfortunately cannot implement it...
MainWindow.h
signals:
void StopDisplayWidget();
void StartDisplayWidget();
void signalFromGUI();
private slots:
void on_pushButton_start_display_clicked();
void on_pushButton_stop_display_clicked();
void on_pushButton_check_clicked();
private:
Ui::MainWindow *ui;
displaythread *threadforDisplay;
display *displayWidget;
QThread *WorkerDisplay;
MainWindow.cpp
{
threadforDisplay = new displaythread;
threadforDisplay->setptr2display(displayWidget);
WorkerDisplay = new QThread;
QObject::connect(WorkerDisplay,SIGNAL(started()),threadforDisplay,SLOT(Process()));
QObject::connect(this,SIGNAL(StartDisplayWidget()),threadforDisplay,SLOT(StartDisplay()));
QObject::connect(this,SIGNAL(StopDisplayWidget()),threadforDisplay,SLOT(StopDisplay()));
QObject::connect(this,SIGNAL(signalFromGUI()),threadforDisplay,SLOT(Check()));
threadforDisplay->moveToThread(WorkerDisplay);
}
void MainWindow::on_pushButton_start_display_clicked()
{
if(!threadforDisplay->IsDisplayActive())
emit this->StartDisplayWidget();
if(!WorkerDisplay->isRunning())
WorkerDisplay->start();
}
void MainWindow::on_pushButton_stop_display_clicked()
{
if(threadforDisplay->IsDisplayActive())
{
emit this->StopDisplayWidget();
}
}
void MainWindow::on_pushButton_check_clicked()
{
std::cout<<"CHECKING SIGNAL SLOT"<<std::endl;
emit this->signalFromGUI();
}
threadforDisplay is a pointer to displaythread class which looks like
displaythread.h
#include <QObject>
#include <QWaitCondition>
#include <QMutex>
#include "display.h"
class displaythread : public QObject
{
Q_OBJECT
public:
explicit displaythread(QObject *parent = 0);
bool IsDisplayActive() const;
void setptr2display(display *);
signals:
public slots:
void Process();
void StartDisplay();
void StopDisplay();
void Check();
private:
void SleepThread();
volatile bool stopped,running;
QMutex mutex;
QWaitCondition waitcondition;
display *displayinGUI;
displaythread.cpp
void displaythread::setptr2display(display *ptr)
{
displayinGUI = ptr;
}
void displaythread::Process()
{
std::cout<<"RECEIVED START PROCESS SIGNAL"<<std::endl;
running = true;
while(true)
{
if(!stopped)
{
displayinGUI->update();
this->SleepThread();
}
}
}
void displaythread::SleepThread()
{
mutex.lock();
waitcondition.wait(&mutex,20);
mutex.unlock();
}
void displaythread::StartDisplay()
{
std::cout<<"RECEIVED START SIGNAL"<<std::endl;
stopped = false;
running = true;
}
void displaythread::StopDisplay()
{
std::cout<<"RECEIVED STOP SIGNAL"<<std::endl;
stopped = true;
running = false;
}
bool displaythread::IsDisplayActive() const
{
return running;
}
void displaythread::Check()
{
std::cout<<"SIGNAL FROM GUI RECEIVED"<<std::endl;
}
display.h
class display : public QWidget
{
Q_OBJECT
public:
explicit display(QWidget *parent = 0);
~display();
signals:
public slots:
private:
void paintEvent(QPaintEvent *);
IplImage *image_opencvBGR,*image_opencvRGB;
QImage image;
CvCapture *webcam;
display.cpp
display::display(QWidget *parent) :
QWidget(parent)
{
image_opencvRGB = cvCreateImage(cvSize(640,480),8,3);
webcam = cvCaptureFromCAM(-1);
}
display::~display()
{
cvReleaseCapture(&webcam);
}
void display::paintEvent(QPaintEvent *)
{
//std::cout<<"IN PAINT LOOP"<<std::endl;
image_opencvBGR = cvQueryFrame(webcam);
cvCvtColor(image_opencvBGR,image_opencvRGB,CV_BGR2RGB);
image = QImage((const unsigned char*)image_opencvRGB->imageData,image_opencvRGB->width,image_opencvRGB->height,QImage::Format_RGB888);
QRectF target(0.0,0.0,image.width(),image.height());
QRectF source(0.0,0.0,image.width(),image.height());
QPainter painter(this);
painter.drawImage(target,image,source);
}
OUTPUT :
RECEIVED START PROCESS SIGNAL
However except the Process slot no other slot is working when signals are emitted from the main gui i.e. MainWindow..is it due to movetoThread command? Donno where i am going wrong..
The answer is simple : Qwidgets don't work outside the main thread. So you cannot execute GUI code using displaythread.
Furthermore your while loop may cause issues (I know the variable is volatile but I dont have the time to analyze properly if it is correct)
See the documentation for more information.
ps: It seems you are overdoing things. Rework your whole design. GUI operations are in the main thread. Use threads for computations only. If the communication between thread and access to their variables use signal and slots only, you dont need locking mechanisms.