Detach tabs from QTabWidget and restore them
-
I have a
QTabWidget
with thetabsClosable
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 aQDialog
. 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 thetabsClosable
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:
- to "copy" the contents to the dialog, it's correct to just set the layout to the pointer of the tab's layout?
- to restore the contents, I'm afraid I'm completely wrong... actually the original widgets are still there... how to retrieve them?
- how to restore the tabs in the initial order, even when a lot of them were detached?
-
@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 usingremoveTab
followed by laterinsertTab
(notaddTab
) 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 usinginsertTab
it will placed at index 1 but it's wrong because DEF should be before GHI. -
@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 useint 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.
-
@Mark81
I may be wrong(!), but I cannot believe it can be right todelete widget
immediately after you have added it back as a tab? Adding widget as tab may re-parent it to theQTabView
, but I don't believe that will copy/new
it, so you mustn'tdelete
it? -
@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)