QApplication not created in main thread()



  • I have created C++ library to convert HTML to PDF using Qt WebKit. But it throws this warning when I convert HTML to PDF in multi threading and generated improper results.

    Can anyone help me to resolve this?


  • Moderators

    @Shidharth Don't create QApplication in other threads than main thread. How and where do you create QApplication instance?



  • @jsulm Thanks for your reply.

    I have created QApplication inside a function, this function is called from .Net web application. While calling this function in .Net console application it works fine. But the error occurs only on web application.

    int arg =1;
    char *  arc = "s";
    QApplication a(arg, &arc, true);

  • Moderators

    Hi @Shidharth,

    1. Does your code create and destroy QApplication multiple times?
    2. Do you create any QObjects before you create QApplication?


  • @JKSH Yes, my code creates and destroy QApplication for each function call.
    No I have not create Qbject before QApplication. The given code snippet was first in the function.



  • @JKSH makes a good point there.

    Anyway, main() is the reception of the executable. A QApplication should be in the main() and be called only once. AFAI.

    Kind Regards,

    Carlos


  • Moderators

    First of all, it is safe to create QApplication in another thread. See here for an example: https://stackoverflow.com/questions/22289423/how-to-avoid-qt-app-exec-blocking-main-thread/22290909#22290909

    Here's how it works. Qt marks the thread which creates the first QApplication instance as the "main thread". You won't get a warning the first time.

    When you destroy that QApplication, Qt does not release all resources. For example, there will still be a hidden global QPixmapCache which needs to be accessed from the QApplication's original thread.

    When you start another thread to create a new QApplication, Qt checks the thread. If Qt detects that you're using a different thread from the first QApplication's thread, then it will give you a warning.

    To avoid the warning and to avoid corruption, you must make sure that the same thread creates the QApplication every time.

    Alternatively, you can create only one QApplication and never destroy it. Every time you want to create a new PDF, do it in that thread.



  • @JKSH I have created single QApplication and using it for multiple times. But it throws error when calling the function multiple times from the Web application, please check the below warnings.

    QObject::setParent: Cannot set parent, new parent is in a different thread
    QObject::installEventFilter(): Cannot filter events for objects in a different thread


  • Moderators

    @Shidharth said in QApplication not created in main thread():

    @JKSH I have created single QApplication and using it for multiple times.

    All the functions for QApplication or Qt WebKit must only be called from the QApplication's thread.

    This means Qt WebKit objects (such as QWebView) must only be created in QApplication's thread.

    But it throws error when calling the function multiple times from the Web application, please check the below warnings.

    QObject::setParent: Cannot set parent, new parent is in a different thread
    QObject::installEventFilter(): Cannot filter events for objects in a different thread

    Your web application starts new threads, so it must not create Qt WebKit objects directly or call Qt WebKit functions.

    Instead, your web application should use emit a signal or use QMetaObject::invokeMethod(). The connection type must be a Qt::QueuedConnection or Qt::BlockingQueuedConnection.

    Here's a very simple example:

    // bridge.h
    Bridge : public QObject
    {
        Q_OBJECT
        
    public:
        Bridge(QObject *parent = nullptr);
        
    public slots:
        void convertHtmlToPdf() {
            QWebView view;
            
            /* Do your PDF conversion here... */
        }    
    };
    
    // In the QApplication thread
    Bridge *bridgePtr = nullptr;
    
    void run()
    {
        int argc = 1;
        char *argv = "s";
        QApplication app(argc, &argv);
    
        // Create the bridge object
        Bridge b;
        bridgePtr = &b;
    
        // Run the QApplication
        app.exec();
    
        // Clean up after the QApplication quits
        bridge = nullptr;
    }
    
    // In another thread
    void convertFromWebApplication()
    {
        QMetaObject::invokeMethod(bridgePtr,
                "convertHtmlToPdf",
                Qt::BlockingQueuedConnection);
    }
    
    void shutdownFromWebApplication()
    {
        QMetaObject::invokeMethod(aApp,
                "quit",
                Qt::BlockingQueuedConnection);
    }
    

    If you want to pass arguments or return arguments, use Q_ARG and Q_RETURN_ARG. See http://doc.qt.io/qt-5/qmetaobject.html#invokeMethod

    Warning: The code above does not do any error checking, and it does not guard against race conditions. You must add those yourself!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.