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-qtBut 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? PutqDebug()
either side of that line too. If it comes before any debug output, it points to a globalQWidget
from another file, though I can't see one in what I looked at. -
To add @JonB suggestions - install a qt message handler, add a breakpoint there and see where it comes from
-
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
-
@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.
-
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 hasQVTKOpenGLNativeWidget
wich is used as a widget where all the graphics is displayed.
I don't use QDesigner but instead I simply setQVTKOpenGLNativeWidget
in layout and display it. But with new VTK 9.0.1 on the line where I create this private var widgetvtkWidget = new QVTKOpenGLNativeWidget();
my program is stopped and the debugger leads me to theQVTKOpenGLNativeWidget.cxx
file as shown on the pciture:
@J-Hilk in all the mentionned files the keyword static is found there:
I use Windows 10 x64, Qt 5.14.0, MSVC 2017
-
@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? -
@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. -
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
and see where it comes from.
-
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 insideMainWindow w
or more precisely in some class insideMainWindow
-
@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 createQWidget
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
andQVTKOpenGLNativeWidget
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