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

Change QGroupBox Layout more than once



  • So in my code I have a QGroupBox that I create in the QtCreator as shown below:
    315d19db-5182-4bb2-9783-682f400e742d-image.png

    What I need is to create radiobuttons inside of it, but it depends on the numbers of buttons saved in my class (l_Questoes is a list of objects of my class), so it need to be generic, and what i'm trying to do is basically this:

    QVBoxLayout *vbox = new QVBoxLayout();
    for (int i = 0; i < static_cast<question_mult*>(l_Questoes[ui->l_prova->row(current)])->alternativas.size(); i++) {
    QRadioButton *button = new QradioButton(static_cast<question_mult*>l_Questoes[ui->l_prova->row(current)])->alternativas[i]);
    vbox->addWidget(button);
    ui->g_alternativas->setLayout(vbox);
    

    I'm creating a layout, adding all the buttons and making my QGroupBox (ui->g_alternativas) get this layout. But I'm receiving this error message:
    QWidget::setLayout: Attempting to set QLayout "" on QGroupBox "g_alternativas", which already has a layout
    Is there a way to break this layout before setting it, or I need to do this in other way?



  • @Zero_emc
    Read the docs https://doc.qt.io/qt-5/qwidget.html#setLayout

    If there already is a layout manager installed on this widget, QWidget won't let you install another. You must first delete the existing layout manager (returned by layout()) before you can call setLayout() with the new layout.



  • Since you are always using a same type of layout, you can keep that layout, but remove all the child widgets, delete them.

    QLayout *layout = ui->g_alternativas->layout();
    QLayoutItem *child;
    while ((child = layout->takeAt(0)) != 0) {
        delete child->widget();
        delete child;
    }
    

    Then add new ones to it.



  • @Zero_emc
    If you do it @Bonnie's way, which is good to retain an existing layout, if you have put more onto the layout than just the widgets I use generically:

        QLayoutItem *wItem;
        while ((wItem = layout.takeAt(0)) != nullptr)
        {
            delete wItem->widget();
            delete wItem->layout();
            delete wItem->spacerItem();
            delete wItem;
        }
    

    EDIT See @Bonnie's reply below. I can't delete this now, but I'd respect his answer more then mine!



  • @JonB Hey, I was also thinking about that.
    But I've checked the source code.

    QLayout * QLayout::layout()
    {
        return this;
    }
    
    QSpacerItem * QSpacerItem::spacerItem()
    {
        return this;
    }
    

    And also in the doc:

    [virtual] QWidget *QLayoutItem::widget()
    If this item manages a QWidget, returns that widget. Otherwise, nullptr is returned.
    Note: While the functions layout() and spacerItem() perform casts, this function returns another object: QLayout and QSpacerItem inherit QLayoutItem, while QWidget does not.

    Those make think that there's no need to delete layout() and spacerItem().
    What do you think?

    [ADDED]
    P.S.But if the child item is a sub-layout, there should be extra code to delete its child items recurringly.



  • @Bonnie
    I'm going to take the 5th on this ;-) My layouts don't actually have spacers or sub-layouts etc. so I never tested that part of the code, I just assumed.... And I didn't bother with recursion because I knew I didn't have any.

    There seems to be a host of suggestions for doing this properly, e.g. https://stackoverflow.com/questions/4857188/clearing-a-layout-in-qt with several different opinions.

    Since I trust you more than myself in this area, I'm actually going to go change my own code to yours since I didn't test all routes in mine! And I'll mark my earlier post with a disclaimer :)



  • @JonB @Bonnie Guys, thank you so much for the answers, now i'm actually questioning if i'm doing it right, I'm still a bit confused about using the Qt Creator to do everything or doing it by code. I think doing it by the Qt Creator i'm chaining all my code to the interface, and it's harder to make it generic. I'll try to understand more everything you guys said and try to adapt my code, thank you!


Log in to reply