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

What is the correct way to show only one instance of QMdiSubWindow?



  • Hello,
    I have a QMdiSubWindow that has a widget inside it. I want to display only one instance of this window. If the user first closes the QMdiSubWindow by clicking on the "X" button, then chooses the menu/action, the same instance should be made visible.

    In the Window with the QMdiArea, I have an instance variable that keeps a reference to the QMdiSubWindow (Thanks to @MRJJ for this suggestion).

    if (! subWindow)
       {
           subWindow= new SubWindow(ui->mdiArea);
       }
       ui->mdiArea->addSubWindow(subWindow);
       subWindow->show();
    

    PROBLEM:
    When I close the subWindow by clicking on the "X" button, and reopen the subWindow (it does reuse the instance), but the widget inside the subWindow is no longer displayed. It is as if the widget inside the subWindow is being released because of the "close" event.

    QUESTION:
    Instead of "close", should I just hide the subWindow when the "X" button is clicked? How do I achieve this?



  • My issue above is similar to this one:
    https://bugreports.qt.io/browse/QTBUG-24919

    I can't believe I have run into a bug in Qt5. I am sure this is a common use case.



  • Found the answer in this post:
    https://www.qtcentre.org/threads/28921-QMdiSubWindow-not-showing-content-when-closed-and-opened-again

    SOLUTION:
    In SubWindow, overrode the show method as follows:

    SubWindow::show()
    {
        subWidget->show();
        QMdiSubWindow::show();
    }
    

    QUESTION:
    The above does solve my problem. But I still don't understand why I need to call show on the widget explicitly. Is it because only a widget recursively calls it's internals to show, whereas a QMdiSubWindow->show() does not recursively call all it's widgets' show? The previous sentence makes sense, because the subWidget was created by me and therefore the framework does NOT know to recursively call show(). However, I am creating subWidget with the QMdiSubWindow as the parent....don't know why that is not enough for Qt to recursively call show()


  • Lifetime Qt Champion

    Hi,

    How are you setting up the content of your QMdiSubWindow ?



  • @SGaist
    As can be seen from the code below: The subWindowWidget is instantiated, and a reference stored in the subWindow. The subWindow is instantiated and a reference stored in the mainWindow. First when the SubWindow is openend it opens normally. Then I close the subWindow by clicking on the "X". When I reopen as shown in the mainwindow at the bottom, using the cached subWindow instace the subWindowWidget will NOT display.

    The subWindowWidget is displayed only if I override the show in the SubWindow class, and also call the subWindowWidget.show().

    The SubWindow.h file:

    class SubWindow : public QMdiSubWindow
    {
    public:
        explicit  SubWindow(QWidget *parent = 0);
        ~SubWindow();
        void show();
    
    private:
        SubWindowWidget *subWindowWidget;
    };
    

    The SubWindow.cpp file: (This shows the overriddent show() method.

    SubWindow::SubWindow(QWidget *parent) :
      QMdiSubWindow(parent)
    {
        subWindowWidget = new SubWindowWidget Widget(this);
        this->setWidget(subWindowWidget );
    }
    
    SubWindow::~SubWindow()
    {
        subWindowWidget ->~SubWindowWidget ();
    }
    
    void SubWindow::show()
    {
        subWindowWidget ->show();
        QMdiSubWindow::show();
    }
    

    The main window action code: ((Thanks to @MRJJ for this suggestion).)

    void MainWindow::openSubWindow()
    {
        if (!subWindow)
        {
            SubWindow = new SubWindow(ui->mdiArea);
            subWindow->setAttribute(Qt::WA_DeleteOnClose,false);
            ui->mdiArea->addSubWindow(subWindow);
        }
        subWindow->show();
    }
    

  • Lifetime Qt Champion

    Don't do that:

    @JohnGa said in What is the correct way to show only one instance of QMdiSubWindow?:

    SubWindow::~SubWindow()
    {
    subWindowWidget ->~SubWindowWidget ();
    }

    Calling object destructors directly might be allowed but it's now how you should use them. See here for some more information.

    As the setWidget documentation explains, you do not have to delete the widget manually, it will be done for you when the sub window is deleted.


  • Lifetime Qt Champion

    Hi

    • Instead of "close", should I just hide the subWindow when the "X" button is clicked? How do I achieve this?
    class MyQMdiSubWindow : public QMdiSubWindow
    {
        Q_OBJECT
    protected:
        void closeEvent( QCloseEvent *closeEvent )
        {
            closeEvent->accept();// eat event
            hide(); // just hide it 
        }
    };
    
    

    and the logic is then (still)

    void MainWindow::on_pushButton_released()
    {
    
        if (!mywin) { // create instance if not have one already
            mywin = new MyQMdiSubWindow();
            ui->mdiArea->addSubWindow(mywin);
        }
    
    // all other cases we just call show again. 
        mywin->show();
    
    }
    
    

Log in to reply