Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt library event loop problems

I'm writing a DLL that is used as a plugin by another application and would like to leverage Qt's abilities.
I have all of the classes set up, compiling and running, but no signals are being emitted. So it seems as though there's no QEventLoop.

Attempt 1:
I modified my main class to subclass QThread instead of QObject, and in the run() create a QEventLoop, connect all signals/slots, and exec the thread.
But it fails saying that you can't have a QEventLoop without a QApplication.

Attempt 2:
I modified the main class (still subclassing the QThraed) to instead instantiate a QCoreApplication, connect all signals/slots, then exec the application.
Warns that the QApplication was not created in the main() thread, and still won't emit signals.

I'm not really sure what to do here. I obviously cannot create a QCoreApplication in the application that will use my plugin, and I cannot emit signals without one.

I have included a simple (and horribly written) test application which should illustrate my problem:

Any help would be appreciated!

main.cpp:

#include <iostream>
#include "ThreadThing.h"
using namespace std;
int main(int argc, char *argv[])
{
    cout << "Main: " << 1 << endl;
    ThreadThing thing1;
    cout << "Main: " << 2 << endl;
    thing1.testStart();
    cout << "Main: " << 3 << endl;
    thing1.testEnd();
    cout << "Main: " << 4 << endl;
    thing1.wait(-1);
    cout << "Main: " << 5 << endl;
    return 0;
}

ThreadThing.h:

#ifndef THREADTHING_H
#define THREADTHING_H
#include <QThread>
class ThreadThing : public QThread
{
    Q_OBJECT
public:
    ThreadThing();
    virtual void run();
    void testStart();
    void testEnd();
public slots:
    void testSlot();
signals:
    void testSignal();
};
#endif//THREADTHING_H

ThreadThing.cpp:

#include "ThreadThing.h"
#include <iostream>
#include <QCoreApplication>

using namespace std;

ThreadThing::ThreadThing()
{
    cout << "Constructor: " << 1 << endl;
    this->start();
    cout << "Constructor: " << 2 << endl;
}

void ThreadThing::run()
{
    cout << "Run: " << 1 << endl;
    int i = 0;
    cout << "Run: " << 2 << endl;
    QCoreApplication* t = new QCoreApplication(i, 0);
    cout << "Run: " << 3 << endl;
    connect(this, SIGNAL(testSignal()), this, SLOT(testSlot()), Qt::QueuedConnection);
    cout << "Run: " << 4 << endl;
    t->exec();
    cout << "Run: " << 5 << endl;
}

void ThreadThing::testStart()
{
    cout << "TestStart: " << 1 << endl;
    emit testSignal();
    cout << "TestStart: " << 2 << endl;
}

void ThreadThing::testEnd()
{
    cout << "TestEnd: " << 1 << endl;
    this->quit();
    cout << "TestEnd: " << 1 << endl;
}

void ThreadThing::testSlot()
{
    cout << "TEST WORKED" << endl;
}

Output:

Main: 1
Constructor: 1
Constructor: 2
Main: 2
TestStart: 1
TestStart: 2
Main: 3
TestEnd: 1
TestEnd: 1
Main: 4
Run: 1
Run: 2
WARNING: QApplication was not created in the main() thread.
Run: 3
Run: 4
like image 812
Marc Avatar asked Nov 23 '09 22:11

Marc


2 Answers

You have to create a QCoreApplication or QApplication and you have to do it in the main thread.

That doesn't mean you can't put the code for that in your plugin... unless the application always runs each plugin in its own thread.

If the application is doing that, then you can try hooking in to whatever native event loop the app uses, and arrange for it to call some function in your plugin in the main thread.

like image 138
rohanpm Avatar answered Sep 30 '22 06:09

rohanpm


I've had success creating a QCoreApplication and running it on a background thread. This is not a standard implementation but can work for simple signal/slot functionality. I did this for a native iOS app with a large legacy Qt codebase.

//I really don't do anything but run on a background thread
class MyQtAppForBackgroundThread : public QCoreApplication 
{
    Q_OBJECT
    ...
}

 //iOS specific code here...
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^(void){
        // This spawns a QCoreApplication on a background thread in an attempt to create something that can
        // queue signals across threads
        qtApp = new MyQtAppForBackgroundThread(smArgc, smArgv);
        qtApp->exec();

    });

Signals fired on the same thread where they were connected will be caught. To catch signals on different threads you must create and poll a QEventLoop on the thread where the signals were created.

//Fire me periodically on the thread the signals and slots were connected
QEventLoop loop;
loop.processEvents( QEventLoop::ExcludeUserInputEvents, 500 );
like image 35
HatAndBeard Avatar answered Sep 30 '22 05:09

HatAndBeard