1
votes

I am having trouble getting my MainWindow to communicate with a Worker thread. I am passing QString object using the usual SIGNAL/SLOT mechhanism. My program should transfer the QString "Alice" from the MainWindow to the worker object of class Worker that is processed in a QThread, and back again. The code compiles without error and runs without hitch using Qt 4.8 and Clang on my MacBook Pro. Here is minimal code displaying my problem.

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <worker.h>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    void ThreadedWork();
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    QString name;
private slots:
    void errorString(QString);

public slots:
    void getFromWorker(QString);

signals:
    void sendToWorker(QString);
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThread>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    name = "Alice";
    qDebug() << "The name in MainWindow is: " << name << " from ThreadID = " << QThread::currentThreadId();
    ThreadedWork();
    qDebug() << "Name sent from the Worker Thread is: " << name;
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::errorString(QString string)
{
    qDebug() << "The error from the threaded process is: " << string;
}

void MainWindow::ThreadedWork()
{
    Worker* worker = new Worker;
    emit sendToWorker(name);
    connect(this,SIGNAL(sendToWorker(QString)),worker,SLOT(getFromMain(QString)));
    connect(worker,SIGNAL(sendToMain(QString)),this,SLOT(getFromWorker(QString)));

    QThread *thread = new QThread;
    worker->moveToThread(thread);

    connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
    connect(thread, SIGNAL(started()), worker, SLOT(process()));
    connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
    connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

    thread->start();
}

void MainWindow::getFromWorker(QString someName) //slot implementation
{
    name = someName;
}

worker.h

#ifndef WORKER_H
#define WORKER_H

#include <QObject>

class Worker : public QObject
{
    Q_OBJECT
public:
    explicit Worker(Worker * parent = 0);
    ~Worker();

signals:
    void sendToMain(QString);
    void error(QString err);
    void finished();

public slots:
    void getFromMain(QString);
    void process();

private:
    QString name;
};

#endif // WORKER_H

worker.cpp

#include "worker.h"
#include <QDebug>
#include <QThread>

Worker::Worker(Worker * parent)
{

}

Worker::~Worker()
{

}

void Worker::process() {
    // allocate resources using new here
    qDebug() << "name recieved from Main is: " << name;
    qDebug() << "name passed to Worker Thread is: " << name << " having ThreadID = " << QThread::currentThreadId();
    emit sendToMain(name);
    emit finished();
}

void Worker::getFromMain(QString someName) // slot implementation
{
    name = someName;
}

My output is:

The name in MainWindow is:  "Alice"  from ThreadID =  0x7fff7de7a300 
Name sent from the Worker Thread is:  "Alice" 
name recieved from Main is:  "" 
name passed to Worker Thread is:  ""  having ThreadID =  0x1107a9000

As is evident above, I am unable to pass the QString "Alice" through to the worker. What am I missing here?

1
Try adding a Qt::QueuedConnection as 5th parameter of connect to worker.Sebastian Lange
One problem is that you emit a signal before you connect a slot to it: emit sendToWorker(name); connect(this,SIGNAL(sendToWorker(QString))...Zlatomir
Can I infer that (and also somewhat obviously) that signals can be emitted in code only after they are connected?marital_weeping
@marital_weeping Of cource, otherwise disconnect() technique will be useless. Documentation says: "Qt's signals and slots mechanism ensures that if you connect a signal to a slot, the slot will be called with the signal's parameters at the right time."t3ft3l--i
@marital_weeping Hi, I have a question about your code. Is possible use finished() signal to send "name" variable to the parent and avoid use sendToMain() signal?Zharios

1 Answers

4
votes

The problem at your ThreadedWork() method:

You firstly emit signal emit sendToWorker(name); and only them connect this one to the slot - this is source of your failure.

Change lines like this:

void MainWindow::ThreadedWork()
{
    Worker* worker = new Worker;

    connect(this,SIGNAL(sendToWorker(QString)),worker,SLOT(getFromMain(QString)));
    connect(worker,SIGNAL(sendToMain(QString)),this,SLOT(getFromWorker(QString)));

    emit sendToWorker(name);

    QThread *thread = new QThread;
    worker->moveToThread(thread);
...
}

I get probably expected results:

The name in MainWindow is:  "Alice"  from ThreadID =  0xcbc
Name sent from the Worker Thread is:  "Alice"
name recieved from Main is:  "Alice"
name passed to Worker Thread is:  "Alice"  having ThreadID =  0xff8