Congratulations to our 2022 Qt Champions!

Widgets doesn't fit to content after hiding



  • Hey,

    I've got a QGroupbox with some widgets. I would like to hide some widgets in some case and show them again. The problem is when I'm hiding widgets the height from the QGroupbox didn't fit to content. I have more space available than I need. When I have more widgets in my Groupbox the space will be more too.

    I set the SizePolicy from my Groupbox to minimum and after hiding the widgets I set a new minimumheight and called adjustSize(). But it doesn't worked. I also tried to call resize(minimumSizeHint()) with no solution.



  • Hi,would you show me some codes about your problem part?



  • Mhm its difficult to figure out what code is relevant but I'll try to paste some snippets together.

    //SizePolicy for the Groupbox
    this->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    
    void MyGBox::minimizeGBox()
    {
        layout->setRowMinimumHeight(2, 0);
        layout->setRowMinimumHeight(4, 0);
        //hiding widgets
        widget1->hide();
        widget2->hide();
        widget3->hide();
    
        //this->setFixedHeight(120);
        //this->setMinimumHeight(120);
        resize(minimumSizeHint());
        this->adjustSize();
    }
    

    Does this helping a little bit?



  • Hi working with Widgets and sizes is sometimes confusing. The widget will only give information about it's desired size or limitations. How the Widget is displayed is up to the layout set. Or the size of the parent Widget and it's layout situation. Don't blame the widget if it's not the proper size. Check out the layout!



  • @heiopei Hi,I am sorry,I spent more time. I try mybest to come true your function.

    main.cpp

    #include "widget.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Widget w;
        w.show();
    
        return a.exec();
    }
    
    

    widget.h

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QWidget>
    #include <QGroupBox>
    #include <QPushButton>
    #include <QVBoxLayout>
    #include <QGridLayout>
    
    namespace Ui {
    class Widget;
    }
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit Widget(QWidget *parent = 0);
        ~Widget();
    private slots:
        void btn1slots();
        void btn2slots();
        void btn3slots();
    private:
        Ui::Widget *ui;
        QGroupBox *groupbox;
        QPushButton *btn1;//I use the button to replace your widget
        QPushButton *btn2;
        QPushButton *btn3;
        QVBoxLayout *layout;
    };
    
    #endif // WIDGET_H
    
    

    widget.cpp

    #include "widget.h"
    #include "ui_widget.h"
    
    Widget::Widget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::Widget)
    {
        ui->setupUi(this);
    
        this->groupbox = new QGroupBox(tr("I am groupBox"),this);
        this->btn1 = new QPushButton(tr("btn1"));
        this->btn2 = new QPushButton(tr("btn2"));
        this->btn3 = new QPushButton(tr("btn3"));
        this->layout = new QVBoxLayout();
    
        layout->addWidget(btn1);
        layout->addWidget(btn2);
        layout->addWidget(btn3);
        groupbox->setLayout(layout);
    
        connect(btn1,SIGNAL(clicked(bool)),this,SLOT(btn1slots()));
        connect(btn2,SIGNAL(clicked(bool)),this,SLOT(btn2slots()));
        connect(btn3,SIGNAL(clicked(bool)),this,SLOT(btn3slots()));
    }
    
    Widget::~Widget()
    {
        delete ui;
    }
    
    void Widget::btn1slots()
    {
        btn1->setHidden(true);//hide the btn1
        layout->removeWidget(btn1);//adn removeWidget(btn1) from layout
        groupbox->adjustSize();//adjustSize
    }
    void Widget::btn2slots()
    {
        btn2->setHidden(true);
        layout->removeWidget(btn2);
        groupbox->adjustSize();
    }
    
    void Widget::btn3slots()
    {
        btn1->setHidden(false);//reshow the btn1 and btn2
        btn2->setHidden(false);
        layout->addWidget(btn1);
        layout->addWidget(btn2);
        groupbox->adjustSize();
    }
    
    

    oh,I said clear?



  • @joeQ
    Wow thank you for your effort. But sadly its still not working. I hide the widgets with setHidden removed it from layout and called adjustSize like in your example. I've got the same result as before. Don't know if its relevant but I'm using a GridLayout.

    @Jeroentjehome
    Mhm do you have any hint? How can I tell my Layout to show the widgets correctly?



  • Does no one have an idea? :(



  • Actually I read this post http://stackoverflow.com/questions/11086801/layout-sizehint-qwidget and tried activate().
    I did a output before and after activate() from sizeHint().height and the result was the same. How is it possible? :(



  • Okay, finally I solved my problem. In addition to delete the widgets I have to delete and init the layout too. So big thanks to joeQ for his help!

    Its workinh like this:

    void clearLayout()
    {
        deleteLayouts();
        deleteWidgets();
        initLayouts();
        initWidgets();
    }


  • Mhm the problem with this solution is, its very inefficient because I need to "hide" serveral widgets at one time. Isn't there a better way to do this? Or is this the only way to delete all the widgets?



  • I stuck with this problem and it took me a few days of deep debugging to completely understand the problem and figure out how to solve it properly...
    Decided to write reply, probably, it will help someone else.

    When I show some widget, the top-level widget(QDialog in my case) extends to fit new content, but when I hide that widget, the size of top-level widget did not change.
    After hiding widget, I tried to call resize(), adjustSize(), setGeometry() and other functions, nothing solved the issue.

    When I show the widget, QWidgetPrivate::setVisible(true) calls QLayout::activate() Synchroneously.
    When I hide the widget, QWidgetPrivate::setVisible(false) post event QEvent::LayoutRequest, which performs QLayout::activate() Asynchroneously.
    So, hiding the widget, did not update the layout, and all resize-functions do nothing, until processing events...

     Qt5Widgets.dll!QWidgetPrivate::setGeometry_sys()
     Qt5Widgets.dll!QWidget::resize()
     Qt5Widgets.dll!QWidget::resize()
     Qt5Widgets.dll!QWidget::setMinimumSize()
     Qt5Widgets.dll!QWidget::setMinimumSize()
     Qt5Widgets.dll!QLayout::activate()
    

    That is call-stack when actual HWND resize happens. Function setGeometry_sys calls ::MoveWindow and perform actual resize.
    And this function was called when I show some widget, but was not called when I hide it.

    https://code.woboq.org/qt5/qtbase/src/widgets/kernel/qlayout.cpp.html#_ZN7QLayout8activateEv
    https://doc.qt.io/qt-6/qlayout.html#SizeConstraint-enum

    There are layout constraits. Default layout constraits says "The main widget's minimum size is set to minimumSize(), unless the widget already has a minimum size."
    So, with default constraits the widget size can only increase to satisfy the minimum size.
    You can try QLayout::SetMinAndMaxSize, but be carefull, all the nested widgets should be on-expandible(without QSizePolicy::ExpandFlag), otherwise it will not work.
    OR, you can try QLayout::SetFixedSize constraints: "The main widget's size is set to sizeHint(); it cannot be resized at all". this flag works perfectly, with the only limitation, the dialog cannot be resized.


Log in to reply