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

Detach tabs from QTabWidget and restore them



  • I have a QTabWidget with the tabsClosable set to true.
    My goal is to "detach" a tab when the related close button is clicked. The tab should be removed and the content placed into a QDialog. Then when this dialog is closed the tab and its content should be restored in the tab bar in the same position. Please note that this must work for all tabs, until only one remain (in that case I disable the tabsClosable property).

    Here what I did so far:

    // DialogPopup is just an empty QDialog
    QMap<QString, DialogPopup *> _mapPopup;
    
    void MainWindow::tabView_tabCloseRequested(int index)
    {
        ui->tabView->tabBar()->removeTab(index);
        QString name = ui->tabView->tabText(index);
    
        DialogPopup *widget = new DialogPopup();
        widget->setWindowTitle(name);
        widget->setLayout(ui->tabView->widget(index)->layout()); // <--- it's correct?
        widget->show();
        connect(widget, &DialogPopup::finished, this, &MainWindow::popup_finished);
        _mapPopup[name] = widget;
    }
    
    void MainWindow::popup_finished(int result)
    {
        Q_UNUSED(result);
    
        DialogPopup *widget = qobject_cast<DialogPopup *>(sender());
        Q_ASSERT(widget);
    
        if (widget)
        {
            QString name = widget->windowTitle();
            ui->tabView->addTab(widget, name);
            delete widget; // <---- it's correct?
            _mapPopup.remove(name);
        }
    }
    

    It doesn't work well and I'm afraid I'm messing up all the pointers :-)

    Questions:

    1. to "copy" the contents to the dialog, it's correct to just set the layout to the pointer of the tab's layout?
    2. to restore the contents, I'm afraid I'm completely wrong... actually the original widgets are still there... how to retrieve them?
    3. how to restore the tabs in the initial order, even when a lot of them were detached?


  • @Mark81
    I don't know the answer to all your stuff, but if you are having issues detaching & restoring the tab then why do you not instead just hide & later re-show it?



  • @JonB because I didn't find the right way to do this. I'm able to hide the tab's content with ui->tabView->widget(index)->hide(), but the tab it's still there. I don't understand how to hide the tab, I can just remove it - and I'm aware the content is not destroyed.



  • @Mark81
    I did not realise that. In which case e.g. https://stackoverflow.com/questions/18394706/show-hide-sub-tab-on-qtabwidget shows an example using removeTab followed by later insertTab (not addTab) to restore it in the correct original place.



  • My code contains the remove tab method, and the pointer to the content's widget should be "stored" into the dialog's one.
    I cannot just insert the tab in the original place because the index might be changed (see question 3).
    For example, this is the initial situation:

    0 ABC, 1 DEF, 2 GHI, 3 JKL

    now I detach tab 1, storing its index in a dialog's property:

    0 ABC, 1 GHI, 2 JKL

    now I detach tab 0, storing its index in a dialog's property:

    0 GHI, 1 JKL

    well, now the dialog DEF has stored the index 1, and ABC index 0.
    If I try to restore tab DEF using insertTab it will placed at index 1 but it's wrong because DEF should be before GHI.


  • Moderators

    @Mark81 There's a bit of logic involved but I'll outline it for you.

    You could, before the first tab removal create a QVector<QWidget*> widgetsInOrder

    than when you try to insert it back into the tabwidget, go through that vector, until you find your current widget pointer.
    go one widget back in the list, and use int QTabWidget::indexOf(QWidget *w) const that index +1 is where you want to insert the widget back in.

    if the returned index is -1 than that widget is also removed from the tabwidget and you have to go one widget more back in the list.



  • @J.Hilk Got it. I'll try this way, thanks! What about question 1 and 2? It's correct to set the layout (which in turn contains the widgets) to the dialog?



  • @Mark81
    I may be wrong(!), but I cannot believe it can be right to delete widget immediately after you have added it back as a tab? Adding widget as tab may re-parent it to the QTabView, but I don't believe that will copy/new it, so you mustn't delete it?


  • Moderators

    @Mark81 said in Detach tabs from QTabWidget and restore them:

    What about question 1 and 2? It's correct to set the layout (which in turn contains the widgets) to the dialog?

    Removing a Widget and passing it to an other Layout is usually how one "moves" widgets around, yes :-)



  • @J.Hilk said in Detach tabs from QTabWidget and restore them:

    Removing a Widget and passing it to an other Layout is usually how one "moves" widgets around, yes :-)

    Unfortunately I'm still doing it wrong. Let's see this short function:

    void MainWindow::tabView_tabCloseRequested(int index)
    {
        QString name = ui->tabView->tabText(index); // retrieve the name of the tab
        QLayout *layout = ui->tabView->widget(index)->layout(); // temporary save the pointer to the content
        ui->tabView->tabBar()->removeTab(index); // remove the tab (now we have only the pointer above to its content)
    
        DialogPopup *widget = new DialogPopup(); // create a new Dialog
        widget->setWindowTitle(name); // set the title like the name of the tab removed
        widget->setLayout(layout); // place here the content of the tab removed
        widget->show(); // show the dialog
    }
    

    The dialog is created with the correct content, but the downside is it clears the content of the next tab (the one after the one removed).

    Why?



  • @Mark81 said in Detach tabs from QTabWidget and restore them:

    ui->tabView->tabBar()->removeTab(index); // remove the tab (now we have only the pointer above to its content)
    

    Here the correct statement:

    ui->tabView->removeTab(index); // remove the tab (now we have only the pointer above to its content)

Log in to reply