Unsolved QMainWindow's content turns black after QMdiSubWindow closes
-
In case of a bug, it's always a good idea to check with the current stable release.
Well, not the same platform, not the same backend, not the same hardware, not the same drivers.
-
@SGaist ok. I made a last test, still under Qt 5.7: taking the code above (loadSubWindow()), simply removing
currentSubWindow->setAttribute(Qt::WA_DeleteOnClose, true);
[EDIT] fixes the issue.
Yet when I keep that line above, but not setting either the QOpenGLWidget in the QScrollQrea, or not setting the QScrollArea in the SubWindow, then there is no glitch when closing the subwindow.
Does that make any sense? That seems to support the implication of the QOpenGLWindow..Can't really remember what made me use the WA_DeleteOnClose... I'm not using a derived class, it's the very QMdiSubWindow class. In your opinion, which is cleaner in this context? Set as true or false? I was afraid of some memory leak so I was inclined to set it to true. I am indeed opening and closing those all the time... They are series of images that can be of a few GB, and loaded as textures in the GPU; and it was unclear when Qt actually destroys theses objects and the widgets set in the QMdiSubWindows.
Let's update to Qt 5.8 anyway and see...
[EDIT] Forgot to write above, simply romeving that line above is enough to fix the problem, with my QOpenGLWidget set in there.
-
I just updated to Qt 5.8. My app won't even start. Crashes immediately, doesn't even load the ui. In debug mode i have the "CDB process terminated". Yet it compiles without issue.
My .pro file was unchanged, looking like this:
QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport TARGET = Lightdrops TEMPLATE = app # CONFIG += console #only for debug win32 { DEFINES += WIN32 INCLUDEPATH += C:/Dev/cfitsio_64 INCLUDEPATH += C:/Dev/libraw INCLUDEPATH += C:\Dev\opencv\build\include INCLUDEPATH += "C:\Program Files\ArrayFire\v3\include" #INCLUDEPATH += C:/dev/exiv2/include #LIBS += -LC:/Dev/exiv2/x64/Debug -llibexiv2 LIBS += -LC:/Dev/cfitsio_64 -lcfitsio LIBS += -LC:/Dev/libraw/lib -llibraw LIBS += -L"C:\Program Files\ArrayFire\v3\lib" -lafopencl LIBS += -LC:\Dev\opencv\build\x64\vc14\lib -lopencv_world320 }
And more info on my projects settings in this screenshot
Any idea?
-
Did you build all the dependencies yourself ?
-
@SGaist Yes, using the same compiler as used in my project. Here only the Qt version changed so I don't understand why the brutal crash, I didn't change anything else.
-
Ok, I had forgotten to include 3 dlls in the directories where the executable lies.
In the previous version, forgetting to do such thing was throwing an error pertaining to that. Here, Qt 5.8 does not say anything in any of the output (application output, console, ...). -
Back to the original issue:
The update did not change anything with the display glitch. So, the only "workaround" is to simply not use
->setAttribute(Qt::WA_DeleteOnClose, true);
This does not relate to the QMdiSubWindow on its own, but to the openGL-related children. Indeed, trying to set that attribute on the QScrollArea (which is set in the QMdiSubWindow) also reproduces the same issue:
currentScrollArea = new QScrollArea(); currentScrollArea->setWidget(rOpenGLWidget); currentScrollArea->setAttribute(Qt::WA_DeleteOnClose, true);
So as far I can see, that attributes messes with QOpenGLWidget. Any idea why? Is this attribute simply not meant to be used in that case? (i.e, having a QOpenGLWidget set in the QScrollArea or QMdiSubWindow)
-
Can you provide a minimal compilable sample that produces this behaviour ? It will makes things easier to analyse and check.
-
@SGaist Thanks for your help. The code is rather messy, so i'm gonna try to scale the code down to the bare minimum than can reproduce this glitch. Will try to finish that in the next hours.
-
It took some time but I nailed it down a bit. So I've written the bare minimum, without the need of my OpenGL shaders (used to display the images as textures).
So starting from a default program with a default ui, and we put only a QMdiArea in it. Then I do this:
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include "winsockwrapper.h" #include <QtCore> #include <QMainWindow> #include <QScrollArea> #include <QMdiSubWindow> #include <ropenglwidget.h> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; ROpenGLWidget *rGLWidget; QScrollArea *scrollArea; QMdiSubWindow *subWindow; }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // Size of the image to display as an openGLTexture QSize oglSize(512, 512); // instantiate the ROpenGLWidget (inherits QOpenGLWidget) rGLWidget = new ROpenGLWidget(this); // Instantiate the QSCrollArea that contains the ROpenGLWidget scrollArea = new QScrollArea(); scrollArea->setWidget(rGLWidget); // Resize it to a slightly larger size than the image itself scrollArea->resize(oglSize + QSize(10, 30)); // Instantiate a QMdiSubWindow subWindow = new QMdiSubWindow; subWindow->setWidget(scrollArea); ui->mdiArea->addSubWindow(subWindow); /// ROpenGLWidget seems to resize only once it has been assigned to the QMdiSubWindow, not before rGLWidget->resize(oglSize); subWindow->resize(scrollArea->size()); subWindow->setAttribute(Qt::WA_DeleteOnClose, true); /// Not sure that's needed here rGLWidget->update(); /// Need to show the subWindows. Does not do it by default all the time. subWindow->show(); } MainWindow::~MainWindow() { delete ui; }
ROpenGLWidget.h
#include <QOpenGLBuffer> #include <QOpenGLTexture> class QPainter; class QOpenGLContext; class QOpenGLPaintDevice; class ROpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT public: ROpenGLWidget(QWidget *parent = 0); ~ROpenGLWidget(); protected: void initializeGL(); void resizeGL(); void paintGL(); private: QOpenGLVertexArrayObject m_vao; QOpenGLBuffer m_vertexBuffer; QOpenGLBuffer m_indexBuffer; }; #endif // RopenGLWidget_H
ROpenGLWidget.cpp
#include "ropenglwidget.h" #include <QApplication> #include <QOpenGLWidget> #include <QtGui/QWindow> #include <QtGui/QOpenGLFunctions> #include <QtGui/QOpenGLShaderProgram> #include <QOpenGLVertexArrayObject> #include <QOpenGLBuffer> #include <QOpenGLTexture> #include <QScreen> ROpenGLWidget::ROpenGLWidget(QWidget *parent) : QOpenGLWidget(parent) , m_vertexBuffer(QOpenGLBuffer::VertexBuffer) , m_indexBuffer(QOpenGLBuffer::IndexBuffer) { setFocusPolicy(Qt::StrongFocus); } ROpenGLWidget::~ROpenGLWidget() { m_indexBuffer.destroy(); m_vertexBuffer.destroy(); m_vao.destroy(); } void ROpenGLWidget::initializeGL() { GLfloat vertices[] = { // Positions // Texture Coords 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // Top Right 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // Bottom Right -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, // Bottom Left -1.0f, 1.0f, 0.0f, 0.0f, 1.0f // Top Left }; GLuint elements[] = { // Note that we start from 0! 0, 1, 3, // First Triangle (first half of the rectangle) 1, 2, 3 // Second Triangle (second half of the rectangle) }; initializeOpenGLFunctions(); glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // Create Vertex Array Object m_vao.create(); // Create Vertex Buffer Object (vbo) m_vertexBuffer.create(); // Create the "element" or "index" buffer object m_indexBuffer.create(); // Bind VAO m_vao.bind(); // Bind Vertex Buffer + check if ( !m_vertexBuffer.bind() ) { qWarning() << "Could not bind vertex buffer to the context"; return; } // Setup Vertex and index Buffer m_vertexBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw); // Send data to vertex buffer, equivalent to glBufferData() m_vertexBuffer.allocate(vertices, sizeof(vertices)); // Bind index Buffer + check if ( !m_indexBuffer.bind() ) { qWarning() << "Could not bind vertex buffer to the context"; return; } m_indexBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw); // Send data to index buffer, equivalent to glBufferData() m_indexBuffer.allocate(elements, sizeof(elements)); } void ROpenGLWidget::paintGL() { } void ROpenGLWidget::resizeGL() { }
So whatever was in painGL() or resize was not causing the glitch. Things are caused by the destructor of ROpenGLWidget at
m_vao.destroy();
and that destructor being called whenever I close the subwindow, it all comes down to that very destructor, and more precisely when destroying the vao.
Removing that line fixes the issue.
My basic openGL courses are a bit far away now, but I thought we needed to destroy the vao... If that's not the case, then ok. But if that is the case, and the vao needs to be destroyed, then why is this doing turning the whole mdiArea all black on a windows pc? Why doesn't it just make the area covered by the content of the QScrollArea all black?Thanks