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

Move QScrollArea between QWidgets



  • As a follow-up of an old thread, I need to move a QScrollArea, that is a page of QTabBar, to a QDialog. This code shows an empty dialog:

    void MainWindow::createTabs(QStringList names)
    {
        foreach (QString name, names)
        {
            QWidget widget = new QWidget();
            QScrollArea *scrollArea = new QScrollArea();
            scrollArea->setWidgetResizable(true);
            scrollArea->setWidget(widget);
            // [...] populate widget with items
            ui->tabView->addTab(scrollArea, name); 
        }
    }
    
    void MainWindow::tabView_tabCloseRequested(int index)
    {
        QScrollArea *area = qobject_cast<QScrollArea *>(ui->tabView->widget(index)); // "save" the tab's widget
        ui->tabView->removeTab(index);
    
        QDialog *dialog = new QDialog(this);
        QVBoxLayout *layoutDialog = new QVBoxLayout();
        layoutDialog->addWidget(area); // "restore" the widget into the dialog
        dialog->setLayout(layoutDialog);
    
        dialog->show();
    }
    

    Instead, if I set the dialog's layout to area->layout() I get the contents but without the QScrollArea.
    Why adding the QScrollArea itself to the new layout doesn't show the contents?


  • Qt Champions 2019

    @Mark81 said in Move QScrollArea between QWidgets:

    QScrollArea *area = qobject_cast<QScrollArea *>(ui->tabView->widget(index)); // "save" the tab's widget
    ui->tabView->removeTab(index);

    You did not even check whether you actually succeeded in getting the scroll area. Also, it could be that after removeTab the scroll area is deleted. You should at least check whether area is a valid pointer and if it is set parent to null to prevent it from being deleted if its parent is deleted.



  • @jsulm said in Move QScrollArea between QWidgets:

    You did not even check whether you actually succeeded in getting the scroll area. Also, it could be that after removeTab the scroll area is deleted. You should at least check whether area is a valid pointer

    mmm... the docs says the page is not actually deleted after removing it:

    Removes the tab at position index from this stack of widgets. The page widget itself is not deleted.

    In my case the page widget is QScrollArea.
    Anyway, now I've checked the validity of area:

    QScrollArea *area = qobject_cast<QScrollArea *>(ui->tabView->widget(index));
    qDebug() << area;
    ui->tabView->removeTab(index);
    qDebug() << area;
    

    QScrollArea(0x332d2b78)
    QScrollArea(0x332d2b78)

    @jsulm said:

    and if it is set parent to null to prevent it from being deleted if its parent is deleted.

    assigning a QWidget to a QLayout doesn't re-parent it?
    Anyway:

    qDebug() << area->parent();
    QVBoxLayout *layoutDialog = new QVBoxLayout();
    layoutDialog->addWidget(area);
    qDebug() << area->parent();
    dialog->setLayout(layoutDialog);
    

    QStackedWidget(0x333eda38, name = "qt_tabwidget_stackedwidget")
    QStackedWidget(0x333eda38, name = "qt_tabwidget_stackedwidget")

    So it seems not - I must remember it wrong.
    I did this:

    qDebug() << area->parent();
    QVBoxLayout *layoutDialog = new QVBoxLayout();
    layoutDialog->addWidget(area);
    area->setParent(dialog);
    qDebug() << area->parent();
    dialog->setLayout(layoutDialog);
    

    QStackedWidget(0x3330da38, name = "qt_tabwidget_stackedwidget")
    QDialog(0x34551b10)

    but still the dialog is empty.


  • Qt Champions 2019

    @Mark81 Just an idea: call show() after adding it to the layout

    layoutDialog->addWidget(area);
    area->show();
    // area->setParent(dialog); <-- remove this
    

    I didn't mean to call setParent() after adding to layout but before removing it from tabView.



  • @jsulm ok, the things begin to work:

    void MainWindow::tabView_tabCloseRequested(int index)
    {
        QScrollArea *area = qobject_cast<QScrollArea *>(ui->tabView->widget(index));
        ui->tabView->removeTab(index);
    
        QDialog *dialog = new QDialog(this);
        dialog->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
    
        QLayout *layoutDialog = new QVBoxLayout();
        layoutDialog->addWidget(area);
        area->show();
        dialog->setLayout(layoutDialog);
    
        dialog->show();
    }
    

    the last (minor) issue is a warning about the geometry:

    setGeometry: Unable to set geometry 116x30+860+469 on QWidgetWindow/'QDialogClassWindow'. Resulting geometry: 116x92+860+469 (frame: 8, 30, 8, 8, custom margin: 0, 0, 0, 0, minimum size: 92x92, maximum size: 16777215x16777215).

    The content is shown but it doesn't fit the initial size of the QDialog. Perhaps I have to manually set its size?


  • Qt Champions 2019

    @Mark81 said in Move QScrollArea between QWidgets:

    dialog->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);

    does it fit without this line?



  • @jsulm no, the QDialog is very small. Of course I can set a size manually, but if I create such a dialog with the same items in Designer (instead of move widgets at run-time) the initial size is set according to the contents.


  • Qt Champions 2019

    @Mark81 You can try to call https://doc.qt.io/qt-5/qwidget.html#adjustSize on the dialog



  • @jsulm with adjustSize() I don't receive anymore the warning about "Unable to set geometry" but still the size of the dialog is the same. Another trial I've done is to create a new QScrollArea and set its content, instead of move the whole QScrollArea from the other widget. Well, in this case the layout is shown correctly (i.e. the dialog's size fits the content) but I surely did it wrong because it add another "frame" or "widget" outside (you see it like a padding where it should not be).


Log in to reply