Сохранить виджеты в таблице квадратом и центрировать их в окне

Я хочу добиться поведения QGridLayout, при котором виджеты, находящиеся внутри, пропорционально увеличивались при увеличении окна, но, сохраняли квадратный размер и местоположение QGridLayout оставалось в центре. Приведу пример того, что я пытаюсь сделать: введите сюда описание изображения введите сюда описание изображения введите сюда описание изображения

Я пытался переопределить heightForWidth:

#include <QtWidgets>

class TestLbl : public QLabel
{
Q_OBJECT

public:
    TestLbl(QWidget* obj = nullptr): QLabel(obj){}
    TestLbl(QString ttl, QWidget* obj = nullptr): QLabel(ttl, obj){}

    bool hasHeightForWidth(  )const override
    {
        return true;
    }

    int heightForWidth( int w )const override
    {
        return w;
    }
};
    
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget widget;
    
    QVBoxLayout l;
    l.addWidget(new QLabel("test"));
    l.addStretch();
    
    
    QGridLayout layout;
    for( int i =0 ; i < 4; i++ )
    {
        layout.setRowStretch( i, 1);
        for ( int j = 0; j < 4; j++)
        {
            layout.setColumnStretch( j, 1 );
            TestLbl *temp = new TestLbl( "1" );
            temp->setFrameStyle(QFrame::Box | QFrame::Plain);
            layout.addWidget( temp, i, j, 1, 1 );
        }
    }
    
    l.addLayout(&layout);
    l.addStretch();
    
    QHBoxLayout bl;
    bl.addWidget(new QLabel("test"));
    bl.addStretch();
    bl.addWidget(new QLabel("test"));
    
    l.addLayout(&bl);
    
    widget.setLayout( &l );
    widget.show();
    a.exec();
    return 0;

}

Но это даёт результат, при котором окно не может свободно менять свой размер, только по диагонали, причем при фуллскрине квадратные элементы вовсе теряются. Главный вопрос: как добиться результата, при котором окно может свободно менять свой размер, QGridLayout центрируется по своей позиции, элементы внутри пропорционально увеличиваются/уменьшаются, при этом оставаясь квадратом? P.S.: я знаю, что в примере много ошибок (объекты на стеке и тд). Это просто пример


Ответы (1 шт):

Автор решения: Chorkov

Желаемого поведения можно добиться жонглируя (кроме heightForWidth) еще и sizeHint, minimalSize, maximalSize... Но проще сразу написать свою процедуру упорядочения элементов на столе (свой Layout). Например, растягивание единственного дочернего элемента в виде максимального квадрата:

#include <QHBoxLayout>
class CentralSquareLayout : public QHBoxLayout
{
public:
    using QHBoxLayout::QHBoxLayout;
    QSize sizeHint       () const { return squareSizeMax( QHBoxLayout::sizeHint   () ); }
    QSize minimumSize    () const { return squareSizeMax( QHBoxLayout::minimumSize() ); }
    QSize maximumSize    () const { return squareSizeMin( QHBoxLayout::maximumSize() ); }
    void setGeometry(const QRect &rect)
    {
        QRect child_rect;
        child_rect.setSize(squareSizeMin(rect.size()));
        child_rect.moveCenter(rect.center());
        for( int i=0; i<count(); ++i)
            itemAt(i)->setGeometry(child_rect);
    }
private:
    static QSize squareSizeMax( QSize s )
    {
        auto m = std::max(s.height(), s.width());
        return QSize( m, m );
    }
    static QSize squareSizeMin( QSize s )
    {
        auto m = std::min(s.height(), s.width());
        return QSize( m, m );
    }
};

Использование:

QVBoxLayout l;
l.addWidget(new QLabel("test"));
l.addStretch(1);

CentralSquareLayout square;

QGridLayout layout;
for( int i =0 ; i < 4; i++ )
{ 
    ... 
}

square.addItem(&layout);

l.addLayout(&square, 1); // второй параметр - насколько нужно растягивать центральный квадрат в сравнении с растягиванием пробелов сверху и снизу
l.addStretch(1);
....
→ Ссылка