I have the following class that I want to later move to a different thread to do it’s work so I don’t stall the UI thread.
class ParserXYZ : public IParser
{
public:
ParserXYZ();
virtual ~ParserXYZ();
virtual void loadData(const QByteArray &data);
virtual void parse();
virtual int getStatus(); //status of parsing, success, error, etc.
virtual QList<Item*> getResult(); //result of parsing
};
My ParserXYZ is hosted in another class, as a member variable.
class DataGatherer : public QObject
{
Q_OBJECT
public:
DataGatherer(IParser *parser, QObject *parent=0);
virtual ~DataGatherer();
void start(const QByteArray &data);
signals:
void finished(QList<Item*>);
private slots:
onParserWorkerFinished();
private:
IParser *m_parser;
};
I made a worker class to to wrap ParserXYZ.
class ParserWorker : public QObject {
Q_OBJECT
public:
ParserWorker(IParser *parser, const QByteArray &data);
virtual ~ParserWorker();
signals:
void finished();
public slots:
void start();
private:
IParser *m_parser;
QByteArray m_data;
};
The methods that orchestrate everything:
//[1]
void DataGatherer::start(const QByteArray &data)
{
QThread *thread = new QThread(this);
ParserWorker *worker = new ParserWorker(m_parser, data);
worker->moveToThread(thread);
connect(thread, SIGNAL(started()), worker, SLOT(start()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(worker, SIGNAL(finished()), this, SLOT(onParserWorkerFinished()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
thread->start();
}
//[2]
void ParserWorker::start()
{
m_parser->loadData(m_data);
m_parser->parse();
emit finished();
}
//[3]
void DataGatherer::onParserWorkerFinished()
{
if (m_parser->getStatus() == 1) {
//was OK
emit finished(m_parser->getResult());
}
}
In a different part of the application, I connect to the DataGatherer’s finished slot:
connect(m_dataGatherer, SIGNAL(finished(QList<Item*>)), this, SLOT(onDataGathererFinished(QList<Item*>)));
void onDataGathererFinished(QList<Item*> items)
{
foreach(Item *item, items)
{
this->insert(item); //this adds elements to a ListView's DataModel
// insert method takes ownership of each Item
// alerts: QObject::setParent: Cannot set parent, new parent is in a different thread
}
}
In my case, //[3] void DataGatherer::onParserWorkerCompleted()
method seems to return on the background thread, not on my main thread. Later when I pump data further via signals I eventually want to add items to a UI element and the program crashes alerting that I am attempting to setParent on an element on a different thread. How can I ensure that my signals return on the main thread?
↧