Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QWidget: Must construct a QApplication before a QWidget



  • Re: How to view dicom images using QT and VTK?

    Hello,
    I wanted to create a Qt application for reading Dicom images using VTK.
    I am using Windows 10, My Qt application version is 5.15.0 and my VTK version is 9.0
    I tried the following code in my Qt application.
    https://github.com/fblupi/read-dicom-series-vtk-qt

    But I get the error as,
    QWidget: Must construct a QApplication before a QWidget
    The program has unexpectedly finished.

    How to deal with this ?



  • @lakshmanGiri
    The main program I see there reads:

    #include <QApplication>
    #include "ReadDICOMSeriesQt.h"
    
    int main(int argc, char** argv) {
        QApplication a(argc, argv);
        ReadDICOMSeriesQt w;
        w.show();
    
        return a.exec();
    }
    

    If yours reads exactly the same, with that QApplication a(argc, argv); as the first statement, it should work. If you have made any change --- in that or any other file --- and failed to say so, show your code.



  • #include <QApplication>

    #include "ReadDICOMSeriesQt.h"

    int main(int argc, char** argv) {
    QApplication a(argc, argv);
    ReadDICOMSeriesQt w;
    w.show();

    return a.exec();
    

    }

    I think the same exact code , but it still shows the mentioned error.



  • @lakshmanGiri
    In the debugger, put a breakpoint on the first line, QApplication a(argc, argv);. Do you get that far at run time, or does the error occur before you hit the breakpoint? Put qDebug() either side of that line too. If it comes before any debug output, it points to a global QWidget from another file, though I can't see one in what I looked at.


  • Lifetime Qt Champion

    To add @JonB suggestions - install a qt message handler, add a breakpoint there and see where it comes from



  • @JonB
    Heyy, Actually I am new to Qt and also came up with something like when the Build is in Debug, the following error occurs but when the build is in Release, the application works.

    Why soo? Can someone please elaborate?.


  • Moderators

    I can't really look into these files

    #include <vtkSmartPointer.h>
    #include <vtkImageViewer2.h>
    #include <vtkDICOMImageReader.h>
    #include <vtkRenderWindow.h>
    #include <vtkRenderWindowInteractor.h>
    #include <vtkRenderer.h>
    

    is there somewhere a static QWidget variable?

    Why soo? Can someone please elaborate?.

    luck


  • Lifetime Qt Champion

    @lakshmanGiri said in QWidget: Must construct a QApplication before a QWidget:

    Actually I am new to Qt

    This is no excuse to not install the message handler and set a breakpoint there in the debugger.


  • Lifetime Qt Champion

    Hi
    Using a message handler is the easiest way to find out what generates this.
    Its not very complicated. Example here.

    https://stackoverflow.com/questions/4954140/how-to-redirect-qdebug-qwarning-qcritical-etc-output



  • Hi,

    I used to work with VTK 9.0.0 and everything was fine. Now I've built VTK 9.0.1 and I get the same error QWidget: Must construct a QApplication before a QWidget in my app.

    More detailled.
    VTK 9 has QVTKOpenGLNativeWidget wich is used as a widget where all the graphics is displayed.
    I don't use QDesigner but instead I simply set QVTKOpenGLNativeWidget in layout and display it. But with new VTK 9.0.1 on the line where I create this private var widget vtkWidget = new QVTKOpenGLNativeWidget(); my program is stopped and the debugger leads me to the QVTKOpenGLNativeWidget.cxx file as shown on the pciture:
    f3b06ed8-7b64-40ae-9112-0a2ffa0fbd2b-image.png

    @J-Hilk in all the mentionned files the keyword static is found there:
    d9565b6f-2bb0-443a-8acb-4823714a2c64-image.png

    I use Windows 10 x64, Qt 5.14.0, MSVC 2017


  • Lifetime Qt Champion

    @Christian-Ehrlicher said in QWidget: Must construct a QApplication before a QWidget:

    To add @JonB suggestions - install a qt message handler, add a breakpoint there and see where it comes from

    ...



  • @Christian-Ehrlicher I havn't ever used qt message handler, but my main.cpp looks like:

    #include <pybind11/embed.h> // everything needed for embedding
    #include <pybind11/pybind11.h>
    #include <pybind11/stl.h>
    namespace py = pybind11;
    
    #include "msvapplication.h"
    #include "mainwindow/mainwindow.h"
    
    #include <QSurfaceFormat>
    #include <QVTKOpenGLStereoWidget.h>
    
    void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
    {
        QByteArray localMsg = msg.toLocal8Bit();
        const char *file = context.file ? context.file : "";
        const char *function = context.function ? context.function : "";
        switch (type) {
        case QtDebugMsg:
            fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
            break;
        case QtInfoMsg:
            fprintf(stderr, "Info: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
            break;
        case QtWarningMsg:
            fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
            break;
        case QtCriticalMsg:
            fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
            break;
        case QtFatalMsg:
            fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
            break;
        }
    }
    
    int main(int argc, char *argv[])
    {
        qInstallMessageHandler(myMessageOutput);
        // needed to ensure appropriate OpenGL context is created for VTK rendering.
        QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());
    
        std::wstring pythonHome( L"C:/Anaconda3/envs/MyEnv38" );
        Py_SetPythonHome(pythonHome.c_str());
        py::scoped_interpreter guard{}; // start the interpreter and keep it alive
    
        qDebug();
        MSVApplication a(argc, argv);
        qDebug();
        MainWindow w;
    
        w.show();
    
        return a.exec();
    }
    
    

    If set a breakpoint anywhere inside myMessageOutput then the app never reaches this function. Probably I dont understand the idea of message handler?


  • Lifetime Qt Champion

    @Please_Help_me_D
    Hi
    It looks good.

    can you have a breakpoint and do
    qDebug() << "Hello" and see if it then stop then?

    The idea of the handler, is that it will then be our code for and used by qDebug function in any code.

    So if the "Must construct a QApplication before a QWidget:"
    is shown in the output panel, then we should be able to catch it.



  • @mrjj hi,

    Yes, now debugger goes to myMessageOutput:
    6d410e34-17e2-40d0-9edf-17e6a4694ab7-image.png

    after I press F10 it goes there:

    7d32d3ba-361a-4cbb-b997-89b5a4b4d9b4-image.png


  • Lifetime Qt Champion

    Hi
    Ok good than its working.
    The trick is now to see if its stops on the error "Must construct a QApplication before a QWidget:"
    (i hope before it crashes)

    When it stops and msg is the right one, you can inspect the call stack
    alt text

    and see where it comes from.



  • @mrjj here are two screenshots
    first screenshot - we haven't reach the error:
    3321067d-edf7-4546-ab47-c2818f394dbe-image.png

    After that I press F10 and we are now in VTK source code. We still have not reached the error:
    4601492e-104e-460d-90dc-94909969280a-image.png

    Then I press F10 once again and error appears:
    0e669b19-4e6c-455a-a3de-957df9320d4a-image.png


  • Lifetime Qt Champion

    So do you actually create a QApplication before instantiating VolumeWidget? I would guess no.



  • @Christian-Ehrlicher I think so. Here is my main function:

    int main(int argc, char *argv[])
    {
        qInstallMessageHandler(myMessageOutput);
        // needed to ensure appropriate OpenGL context is created for VTK rendering.
        QSurfaceFormat::setDefaultFormat(QVTKOpenGLStereoWidget::defaultFormat());
    
        std::wstring pythonHome( L"C:/Anaconda3/envs/MyEnv38" );
        Py_SetPythonHome(pythonHome.c_str());
        py::scoped_interpreter guard{}; // start the interpreter and keep it alive
    
    /* Here I create my application */
        qDebug() << "Hello";
        MSVApplication a(argc, argv); // This Class is inherited from QApplication
        qDebug() << "Bye bye :)";
        MainWindow w;
    
    
        w.show();
        return a.exec();
    }
    

    and VolumeWidget is instantiated inside MainWindow w or more precisely in some class inside MainWindow


  • Lifetime Qt Champion

    @Please_Help_me_D said in QWidget: Must construct a QApplication before a QWidget:

    MSVApplication

    Please show the ctor



  • @Christian-Ehrlicher I didn't understood what is the "ctor" but I think you wanted to see MSVApplication:

    Header:

    #ifndef MSVAPPLICATION_H
    #define MSVAPPLICATION_H
    
    #include "core/h5core.h"
    
    #include "DockManager.h"
    #include "DockWidget.h"
    #include "DockWidgetTab.h"
    #include "DockAreaWidget.h"
    #include "DockAreaTitleBar.h"
    #include "DockAreaTabBar.h"
    #include "FloatingDockContainer.h"
    #include "DockComponentsFactory.h"
    
    #include <QApplication>
    
    class AppSettings;
    
    class MSVApplication : public QApplication
    {
        Q_OBJECT
    
    public:
        MSVApplication(int &argc, char **argv);
        ~MSVApplication() override;
    
        int findVisDockByName(QString dockName);
    
        void setDockManager(ads::CDockManager* dockManager);
    
        ads::CDockManager* getDockManager();
        ads::CDockWidget* getCurrentVisDock();
        QList<ads::CDockWidget*> getVisDockList();
        h5core::WindowType getCurrentWindowType();
        int getCurrentVisDockNum();
        int getVisDockListCount();
    
    signals:
       void currentVisDockChanged(ads::CDockWidget* dockWidget, int num);
       void visDockAdded(ads::CDockWidget* dockWidget, int num);
       void visDockRemoved(ads::CDockWidget* dockWidget, int num);
    
    private slots:
       void onFocusedDockChanged(
               ads::CDockWidget* old, ads::CDockWidget* now);
       void onDockAdded(ads::CDockWidget* visDock);
       void onDockAboutToBeRemovedRemoved(ads::CDockWidget* visDock);
    
    private:
       ads::CDockManager* dockManager;
       int currentVisDockNumber = -1;
       QList<ads::CDockWidget*> visDockList;
       AppSettings* appSettings;
    };
    
    #endif // MSVAPPLICATION_H
    
    

    Implementation:

    #include "msvapplication.h"
    
    #include "core/appsettings.h"
    
    MSVApplication::MSVApplication(int &argc, char **argv):
        QApplication(argc, argv)
    {
        appSettings = new AppSettings();
    }
    
    MSVApplication::~MSVApplication(){
        delete appSettings;
    }
    
    int MSVApplication::findVisDockByName(QString dockName){
        for (int i = 0; i < visDockList.count(); i++){
            if (visDockList[i]->windowTitle() == dockName)
                return i;
        }
        return -1;
    }
    
    void MSVApplication::setDockManager(ads::CDockManager* dockManager){
        this->dockManager = dockManager;
    
        connect(dockManager, &ads::CDockManager::focusedDockWidgetChanged,
                this, &MSVApplication::onFocusedDockChanged);
        connect(dockManager, &ads::CDockManager::dockWidgetAdded,
                this, &MSVApplication::onDockAdded);
        connect(dockManager, &ads::CDockManager::dockWidgetAboutToBeRemoved,
                this, &MSVApplication::onDockAboutToBeRemovedRemoved);
    }
    
    ads::CDockManager* MSVApplication::getDockManager(){
        return this->dockManager;
    }
    
    ads::CDockWidget* MSVApplication::getCurrentVisDock(){
        return dockManager->focusedDockWidget();
    }
    
    QList<ads::CDockWidget*> MSVApplication::getVisDockList(){
        return visDockList;
    }
    
    h5core::WindowType MSVApplication::getCurrentWindowType(){
        if (!getCurrentVisDock())
            return static_cast<h5core::WindowType>(0);
    
        int windowType = getCurrentVisDock()->property("WindowType").toInt();
        return static_cast<h5core::WindowType>(windowType);
    }
    
    int MSVApplication::getCurrentVisDockNum(){
        return currentVisDockNumber;
    }
    
    int MSVApplication::getVisDockListCount(){
        return visDockList.count();
    }
    
    void MSVApplication::onFocusedDockChanged(
            ads::CDockWidget* old, ads::CDockWidget* now){
        int num = -1;
        for (int i = 0; i < visDockList.count(); i++){
            if (now == visDockList[i]){
                num = i;
                break;
            }
        }
    
        if (num == -1)
            return;
    
        currentVisDockNumber = num;
        emit currentVisDockChanged(now, currentVisDockNumber);
    
        qDebug() << now->windowTitle();
    }
    
    void MSVApplication::onDockAdded(ads::CDockWidget* visDock){
        if (!visDock->features()
                .testFlag(ads::CDockWidget::DockWidgetFocusable))
            return;
    
        visDockList.push_back(visDock);
        emit visDockAdded(visDock, visDockList.count()-1);
    }
    
    void MSVApplication::onDockAboutToBeRemovedRemoved(ads::CDockWidget* visDock){
        int num = -1;
        for (int i = 0; i < visDockList.count(); i++){
            if (visDock == visDockList[i]){
                num = i;
                break;
            }
        }
    
        if (num == -1)
            return;
    
        visDockList.removeAt(num);
        emit visDockRemoved(visDock, num);
    }
    
    

    By the way my VolumeWidget is able to create QWidget without problem:

    void VolumeWidget::init(){
        sortWidget = new SortWidget();
    
    /* no preblem to create widget here */
        QWidget* myWidget = new QWidget();
    
    /* but when creating VTK widget I get error */ 
        vtkWidget = new QVTKOpenGLNativeWidget();
        vtkWidget->setEnableHiDPI(true);
    
        QVBoxLayout* mainVLayout = new QVBoxLayout(this);
        mainVLayout->setContentsMargins(0, 0, 0, 0);
        mainVLayout->addWidget(sortWidget);
        mainVLayout->addWidget(vtkWidget);
    }
    

    IMPORTANT! I just remembered one thing from VTK documentation. There is said something about Qt restriction. Please look general info about these two classes (QVTKOpenGLStereoWidget and QVTKOpenGLNativeWidget each of those can be replaced by another) from these two links:
    https://vtk.org/doc/nightly/html/classQVTKOpenGLStereoWidget.html#details
    https://vtk.org/doc/nightly/html/classQVTKOpenGLNativeWidget.html#details



  • @Please_Help_me_D

    Hello! The ctor means constructor. I would suggest to add this code to your main.cpp.

    #ifdef QT_DEBUG
        qputenv("QT_FATAL_WARNINGS", "1");
        qputenv("QT_MESSAGE_PATTERN",
                "Type: %{type}\nProduct Name: %{appname}\nFile: %{file}\nLine: %{line}\nMethod: %{function}\nThreadID: %{threadid}\nThreadPtr: %{qthreadptr}\nMessage: %{message}");
    #endif
    

    It will work only in the debug mode, so you can properly identify what causes that issue. I had the similar issue but with "QPixmap: Must construct a QGuiApplication before a QPixmap", this was really annoying issue, because I could not identify it properly, but when I have used the code above I have found out what causes it and fixed it. The actual problem with my issue was that QPixmap/QIcon was created in the QThread worker class and added using signals/slots to main thread. I have fixed it by sending only paths for those icons from the worker class and creating the actual icons in the main thread. Also, feel free to check out the Qt source code for this error (the above code will help you find the actual file), it will help you understand what causes it and how to fix it.



  • @Cobra91151 thank you for help.
    I just set those few lines of code in my main(...) func:

    int main(int argc, char *argv[])
    {
    #ifdef QT_DEBUG
        qputenv("QT_FATAL_WARNINGS", "1");
        qputenv("QT_MESSAGE_PATTERN",
                "Type: %{type}\nProduct Name: %{appname}\nFile: %{file}\nLine: %{line}\nMethod: %{function}\nThreadID: %{threadid}\nThreadPtr: %{qthreadptr}\nMessage: %{message}");
    #endif
    
        qInstallMessageHandler(myMessageOutput);
        // needed to ensure appropriate OpenGL context is created for VTK rendering.
        QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());
    
        std::wstring pythonHome( L"C:/Anaconda3/envs/MyEnv38" );
        Py_SetPythonHome(pythonHome.c_str());
        py::scoped_interpreter guard{}; // start the interpreter and keep it alive
    
        qDebug() << "Hello";
        MSVApplication a(argc, argv);
        qDebug() << "Bye bye :)";
        MainWindow w;
    
        w.show();
        return a.exec();
    }
    
    

    As I understood from the documentation qputenv() sets environment variable but I can't find those two variables (QT_FATAL_WARNINGS and QT_MESSAGE_PATTERN) neither in Qt project settings or Windows environment variables.
    Could you explain how to get profit from those lines of code?


  • Lifetime Qt Champion

    @Please_Help_me_D said in QWidget: Must construct a QApplication before a QWidget:

    I can't find those two variables

    You have to set them.
    "Qt project settings or Windows environment variables" - of course not as those are neither project settings nor Windows environment variables (Windows does not know anything about these two variables). Those are environment variable which you can set (either in QtCreator in "Run environment" or in the terminal where you start your app).



  • @jsulm I just set those variables like you can see in the picture:
    6d5c34e4-be56-46e2-b89f-73e572a8d3df-image.png

    Now when I launch the app I get app output:
    Type: fatal\nProduct Name: \nFile: unknown\nLine: 0\nMethod: unknown\nThreadID: 11772\nThreadPtr: 0x190cb3ac290\nMessage: QWidget: Must construct a QApplication before a QWidget

    I think I misunderstood something



  • @Please_Help_me_D
    One thing: do you/something have a global/static QWidget variable (not pointer to one) anywhere? That is not allowed, as per the error message.



  • @JonB all widgets in my app are created as pointers. Also I don't have any static method() wich returns non-pointer qwidget.
    But probably VTK library has something that returns non-pointer widget. @J-Hilk asked something similar and my answer was here


  • Lifetime Qt Champion

    Maybe the VTK lib links against another Qt version? Really strange behavior.



  • @Christian-Ehrlicher I use Qt 5.14.2 and the person who started the topic uses Qt 5.15.0
    VTK had prerelease version 9.0.0 wich works fine on my PC. Then they released full VTK 9.0.1 (newest release) wich gives me mentionned error.
    Both releases were built as shared libs.

    Probably I should ask this question in VTK forum



  • If I use class MSVApplication : public QApplication then is my MSVApplication (created in main.cpp) able to return QWidget*?
    Please look at my implementation of MSVApplication() is it fine?

    #ifndef MSVAPPLICATION_H
    #define MSVAPPLICATION_H
    
    #include "core/h5core.h"
    
    #include "DockManager.h"
    #include "DockWidget.h"
    #include "DockWidgetTab.h"
    #include "DockAreaWidget.h"
    #include "DockAreaTitleBar.h"
    #include "DockAreaTabBar.h"
    #include "FloatingDockContainer.h"
    #include "DockComponentsFactory.h"
    
    #include <QApplication>
    
    class AppSettings;
    
    class MSVApplication : public QApplication
    {
        Q_OBJECT
    
    public:
        MSVApplication(int &argc, char **argv);
        ~MSVApplication() override;
    
        int findVisDockByName(QString dockName);
    
        void setDockManager(ads::CDockManager* dockManager);
    
        ads::CDockManager* getDockManager(); // ads::CDockManager* inherited from QWidget*
        ads::CDockWidget* getCurrentVisDock(); // ads::CDockManager* inherited from QWidget*
        QList<ads::CDockWidget*> getVisDockList();
        h5core::WindowType getCurrentWindowType();
        int getCurrentVisDockNum();
        int getVisDockListCount();
    
    signals:
       void currentVisDockChanged(ads::CDockWidget* dockWidget, int num);
       void visDockAdded(ads::CDockWidget* dockWidget, int num);
       void visDockRemoved(ads::CDockWidget* dockWidget, int num);
    
    private slots:
       void onFocusedDockChanged(
               ads::CDockWidget* old, ads::CDockWidget* now);
       void onDockAdded(ads::CDockWidget* visDock);
       void onDockAboutToBeRemovedRemoved(ads::CDockWidget* visDock);
    
    private:
       ads::CDockManager* dockManager;
       int currentVisDockNumber = -1;
       QList<ads::CDockWidget*> visDockList;
       AppSettings* appSettings;
    };
    
    #endif // MSVAPPLICATION_H
    
    


  • I'm really sorry that was my mistake.
    I've found out that when building newest VTK 9.0.1 my CMAKE cofiguration used to contain all Qt settings (QtDir and other Qt path to Qt cmake files they were automatically set from PATH var and I didn't check them) from python PySide2 Qt. So right after I have set the correct Qt dirs and rebuild VTK 9.0.1 it began to work fine !

    Thank you for your effort and especially to @Cobra91151 who spent many hours trying to solve my problem


Log in to reply