[SOLVED] QWidget: Must construct a QApplication before a QWidget



  • Hello,

    I am working on a project with Qt 5.2.1. and VTK 6.1.

    For the visualization I am trying to implement a MeshWrapper class that spawns multiple QVTKWidgets as Mdi windows.
    When I try to instantiate a new mdi child from my MeshWrapper class I get the error:
    @QWidget: Must construct a QApplication before a QWidget@

    Afterwards the program execution stops.

    When instantiating it directly from the mainwindow it works fine!

    I read that this error can occur, when the Widget gets declared somewhere in the header before the QApplication is created, but the mdi child is only created in a function of the MeshWrapper which is called from the mainwindow.

    Can anyone help me resolve this error?

    Thank You

    @class MeshWrapper : public QObject
    {
    Q_OBJECT
    public:
    MeshWrapper();

    bool loadFile(const QString &fileName);
    bool createMeshes(QMdiArea *mdiArea);
    

    signals:

    public slots:

    private:
    vtkSmartPointer<vtkPolyData> polyData[2];
    };@

    @bool MeshWrapper::createMeshes(QMdiArea *mdiArea) {
    mdiVTKChild *mesh1 = new mdiVTKChild();
    mesh1->render();

    mdiArea->addSubWindow(mesh1);
    mesh1->show();
    
    return true;
    

    }@

    @class mdiVTKChild : public QVTKWidget
    {
    Q_OBJECT
    public:
    mdiVTKChild();
    mdiVTKChild(vtkSmartPointer<vtkPolyData> _polyData);

    bool loadFile&#40;const QString &fileName&#41;;
    bool render(&#41;;
    

    signals:

    public slots:

    private:
    vtkSmartPointer<vtkPolyData> polyData;
    };@

    @void MainWindow::on_actionRead_Liver_triggered()
    {
    QString filename = QFileDialog::getOpenFileName(this,tr("Open File"), "C:/", tr("(*.txt)"));

    MeshWrapper *meshWrapper = new MeshWrapper();
    meshWrapper->loadFile&#40;filename&#41;;
    meshWrapper->createMeshes(ui->mdiArea&#41;;
    

    }
    @


  • Moderators

    Can you post the main function here, too?



  • Thank you for your reply. This is the main function:

    @#include "mainwindow.h"
    #include <QApplication>

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    MainWindow w;
    w.showMaximized();

    return a.exec&#40;&#41;;
    

    }@


  • Moderators

    Hm, that looks good.

    ... apart from the fact that you indeed are including QApplication header after mainwindow.h, which is precisely what you warned agains in your initial post ;P

    Still, it should work, IMO.



  • I just switched the 2 includes, no difference. The main function was generated by QtCreator.
    Also it works when I create the mdi child directly in the mainwindow, which confuses me.

    Is it possible that it happens, because the MeshWrapper base is QObject and not QWidget?


  • Moderators

    Just for fun, you might set a breakpoint at the instantiation of your QApplication and in the ctor of your MeshWrapper class, just to see for yourself which is being instantiated first.


  • Moderators

    Ah, I have missed that part. In theory, it should not be a problem, although it might indicate that a better idea would be to clearly separate the logic from the UI (might help a lot down the line): so, move the widget creation to your GUI classes.

    Remove the brackets from this line, too:
    @
    // old
    mdiVTKChild *mesh1 = new mdiVTKChild();

    // new
    mdiVTKChild *mesh1 = new mdiVTKChild;
    @

    Also, please be careful with your mesh1->render() function: you are instantiating the mdiVTKChild without a parent, so it will be created as a separate window. Maybe modify your code and pass the QMdiArea as parent for mdiVTKChild?



  • Thank you for your replies.

    bq. Just for fun, you might set a breakpoint at the instantiation of your QApplication and in the ctor of your MeshWrapper class, just to see for yourself which is being instantiated first.

    I did that. QApplication is being instantiated before any GUI is shown and MeshWrapper much later.

    I also did what sierdzio said, but no success either.

    This error keeps me busy for two days now... Any more ideas?



  • If you are getting this error exactly on
    @
    mdiVTKChild *mesh1 = new mdiVTKChild();
    @

    Add a debug output for qApp before creating mdiVTKChild.
    You may need to include QApplication to get qApp.
    @
    #include <QApplication>
    ...
    qDebug() << qApp;
    mdiVTKChild *mesh1 = new mdiVTKChild();
    ...
    @



  • Yes, it happens exactly on this line, but only if it is called from the MeshWrapper class.

    I did what you said, this is the output:

    @
    QApplication(0xa99640fae0)
    QWidget: Must construct a QApplication before a QWidget
    @

    Looks like qApp exists, doesn't it?



  • "It's not possible" (c) Boris the animal from MIB3
    @
    QApplication(0xa99640fae0)
    QWidget: Must construct a QApplication before a QWidget
    @

    Apparently we are loosing qApp between this new operator and QWidget() constructor.

    Could you put here a source for mdiVTKChild constructor.

    Could you step in inside mdiVTKChild() constructor and then inside QWidget() in debugger.



  • These are two constructors:

    @mdiVTKChild::mdiVTKChild(QWidget *parent, vtkSmartPointer<vtkPolyData> _polyData) :
    QVTKWidget(parent)
    {
    polyData = _polyData;
    }

    mdiVTKChild::mdiVTKChild(vtkSmartPointer<vtkPolyData> _polyData)
    {
    setAttribute(Qt::WA_DeleteOnClose);
    this->setMinimumSize(QSize(300, 300));

    polyData = _polyData;
    

    }

    @

    The error appears for both of them. The program stops, before the debugger breaks on them.

    If I step in from the instantiation of the child, I get to the header of the constructor and stops there.

    What could that mean?



  • In you header file you have declared two constructors.
    One default and one with _polyData as a parameter.
    @
    public:
    mdiVTKChild();
    mdiVTKChild(vtkSmartPointer<vtkPolyData> _polyData);
    @

    In your source code you don't have default constructor but there is another non-default constructor.
    @
    mdiVTKChild::mdiVTKChild(QWidget *parent, vtkSmartPointer<vtkPolyData> _polyData) : QVTKWidget(parent)
    {
    polyData = _polyData;
    }

    mdiVTKChild::mdiVTKChild(vtkSmartPointer<vtkPolyData> _polyData)
    {
    ...
    }
    @

    When you creating new mdiVTKChild object you are calling a default constructor, which is declared but not defined.
    @
    bool MeshWrapper::createMeshes(QMdiArea *mdiArea)
    {
    mdiVTKChild *mesh1 = new mdiVTKChild();
    ...
    }
    @

    Is it possible that you are mixing some old and new code and getting a memory corruption because of that?



  • Actually I changed both, the header and the implementation. I just forgot to post the new header:

    @public:
    mdiVTKChild(QWidget *parent, vtkSmartPointer<vtkPolyData> _polyData);
    mdiVTKChild(vtkSmartPointer<vtkPolyData> _polyData);
    @

    Sorry for the confusion. But I would be happy if that was the problem :D



  • And you are sure that VTKWidget does not try to create any global QWidgets.
    And there no other threads that were started by some global variables and try to create mdiVTKChild before QApplication is created.

    If so then I think you need to go (debug) deeper.

    But before that. Try to create a small (as small as possible) application that just creates mdiVTKChild.
    Does it produce the same error?

    Now to the debugger.
    Run your app with gdb in command line not in qtcreator.
    This "link":http://stackoverflow.com/questions/58851/can-i-set-a-breakpoint-on-memory-access-in-gdb/59146#59146 explains how to set a breakpoint on a memory access.

    Modify main()
    @
    ...
    QApplication a(argc, argv);
    qDebug() << "qApp =" << qApp << "address of qApp =" << &qApp;
    ...
    @

    • Add a breakpoint on main() step through qDebug() and see what address do you have.
    • Put memory access breakpoint on that address and run you app.
    • See if qApp will be changed before you will get that "must construct" error.


  • I will try the deeper debugging. But to answer your question:

    It only gives me the error when I create mdiVTKChild inside the MeshWrapper class.
    When I call "new mdiVTKChild" from my mainwindow.cpp in the function it works.

    Works:

    @void MainWindow::on_actionRead_Liver_triggered()
    {
    QString filename = QFileDialog::getOpenFileName(this,tr("Open File"), "C:/", tr("(*.txt)"));

    mdiVTKChild *mesh1 = new mdiVTKChild();
    mesh1->loadFile&#40;filename&#41;;
    mesh1->render();
    
    ui->mdiArea->addSubWindow(mesh1);
    mesh1->show();
    

    }@

    Doesnot work:

    @void MainWindow::on_actionRead_Liver_triggered()
    {
    QString filename = QFileDialog::getOpenFileName(this,tr("Open File"), "C:/", tr("(*.txt)"));

    MeshWrapper *meshWrapper = new MeshWrapper();
    meshWrapper->loadFile&#40;filename&#41;;
    meshWrapper->createMeshes(ui->mdiArea);
    

    }
    @



  • Have you tried to pass ui->mdiArea to mdiVTKChild() as a parent widget?



  • Yes, but that makes no difference.

    But I think I was able to narrow it down:

    I was wondering if it could have something to do with the fact, that the child is a QVTKWidget and not a QWidget, so I changed the base of the class and threw out all the VTK stuff. Apparently that works.

    So it has something to do with the QVTKWidget. But why does QVTKWidget work, when created in the mainwindow?

    I will try to debug the QVTKWidget, perhaps it's just something I missed to pass to the MeshWrapper from the mainwindow...



  • bq. But why does QVTKWidget work, when created in the mainwindow?

    Is it possible that in case of error you are trying to create QVTKWidget not in main GUI thread?



  • I finally made it. After pinning it on the QVTKWidget I was sure it was VTKs fault and not my code.
    I guessed it is much more likely, that I made an error building and linking VTK on my machine than an error in VTK.
    So I reworked everything and included the information I found here:
    http://public.kitware.com/pipermail/vtkusers/2011-August/069256.html

    After some playing around it finally worked.

    Sorry for bugging you with Qt questions, when in the end it was a matter of combining Qt and VTK, but thank you so much for your ongoing participation and effort in finding my error :)



  • Great and thank you for sharing a solution.
    Could you put [SOLVED] in the title of your original message.


Log in to reply
 

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