QMainWindow's content turns black after QMdiSubWindow closes



  • Hi,

    I have a display glitch in my GUI when I close subwindows in an MDI area.
    My GUI is made with Qt Creator. Qt 5.7.1, Qt Creator 4.2.0. This issue never occurs on mac, but it occurs on every windows pc tested so far, either NVIDIA or Intel graphics.

    Here are more details:

    My MainWindows header starts like this:

    namespace Ui {
    class RMainWindow;
    }
    
    class RMainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit RMainWindow(QWidget *parent = 0);
        ~RMainWindow();
    

    And the .cpp

    using namespace std;
    
    RMainWindow::RMainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::RMainWindow),
        currentROpenGLWidget(NULL)
    {
        ui->setupUi(this);
        this->showMaximized();
        setCentralWidget(ui->mdiArea);
    

    So right here I setup my QMdiArea that comes from the ui.

    '''currentROpenGLWidget''' is an object that inherits a QOpenGLWidget. I indeed display images in there as textures using my own shaders. This QOpenGLWidget is set in a QScrollArea (so I can scroll through large textures horizontally and vertically). And the latter is set in a QMdiSubwindow, as follows:

    void RMainWindow::loadSubWindow(QScrollArea *scrollArea)
    {
        currentSubWindow = new QMdiSubWindow;
        currentSubWindow->setWidget(scrollArea);
        ui->mdiArea->addSubWindow(currentSubWindow);
        currentSubWindow->setAttribute(Qt::WA_DeleteOnClose, true);
    }
    

    The purpose of this method is to open a new subwindow when I drag an image file into the QMdiArea. The subwindow displays, and I can scroll through the image (see screenshot1 and screenshot 2).
    I can load more windows without issues.
    The problems occur when I close one of the subwindows. The content of the RMainWindow's, including the docks, turns black, some elements of the GUI sometimes remain visible, but that's a bit random, most of the time it's all black. Then if I hover the move on either dock (right-hand side or bottom), then the buttons show up again but the glitch persists everywhere else: see screenshot 3 and screenshot 4
    Sometimes if I click on the button that takes the window out of full screen mode, everything somewhat refresh and would show up normally again, only sometimes.

    Of course, there are more codes than what I show, for resizing the different windows when they first show up, to the size I prefer, but I prefer to limit copy pasting code 'cause maybe you'll already see a problem here. If not, I can show more.

    Do you think the QMdiArea needs some explicit refresh or update() after closing a window? If yes, what would be the cleanest way to do it? Through a connect maybe?

    Thanks for the help


  • Lifetime Qt Champion

    Hi,

    There might be something going in with your OpenGL widget. Can you check whether it's still the case with Qt 5.8 ?



  • @SGaist Hmm... ok, i've been hoping it would not be the QOpenGLWidget, so far it's been my weak spot. I'll update and give it a try. What makes you think Qt 5.8 can solve this? What changed in the QOpenGLWidget class that could relate to this? Any theory on why it's working on mac without issue?


  • Lifetime Qt Champion

    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?


  • Lifetime Qt Champion

    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)


  • Lifetime Qt Champion

    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.



  • @SGaist

    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


Log in to reply
 

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