Макеты Qt - Сохранять пропорции виджета при изменении размера

Я хочу сохранить соотношение сторон 16/9 на QGroupBox (то, что слева на скриншоте ниже). Для тестов я сделал простую программу с 4 групповыми блоками в вертикальном расположении, все в горизонтальном расположении:

main.cpp

#include "MainWindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();


private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "MainWindow.h"
#include "ui_MainWindow.h"

#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    qDebug() << "horizontalLayout->hasHeightForWidth: " << ui->horizontalLayout->hasHeightForWidth();
}

MainWindow::~MainWindow()
{
    delete ui;
}

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>1000</width>
    <height>703</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QHBoxLayout" name="horizontalLayout">
    <item>
     <widget class="GroupBoxHFW" name="groupBox_1">
      <property name="title">
       <string>GroupBox</string>
      </property>
     </widget>
    </item>
    <item>
     <layout class="QVBoxLayout" name="verticalLayout">
      <item>
       <widget class="QGroupBox" name="groupBox_2">
        <property name="minimumSize">
         <size>
          <width>485</width>
          <height>204</height>
         </size>
        </property>
        <property name="maximumSize">
         <size>
          <width>485</width>
          <height>204</height>
         </size>
        </property>
        <property name="title">
         <string>GroupBox</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QGroupBox" name="groupBox_3">
        <property name="minimumSize">
         <size>
          <width>485</width>
          <height>204</height>
         </size>
        </property>
        <property name="maximumSize">
         <size>
          <width>485</width>
          <height>204</height>
         </size>
        </property>
        <property name="title">
         <string>GroupBox</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QGroupBox" name="groupBox_4">
        <property name="minimumSize">
         <size>
          <width>485</width>
          <height>204</height>
         </size>
        </property>
        <property name="maximumSize">
         <size>
          <width>485</width>
          <height>204</height>
         </size>
        </property>
        <property name="title">
         <string>GroupBox</string>
        </property>
       </widget>
      </item>
      <item>
       <spacer name="verticalSpacer">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
        </property>
        <property name="sizeHint" stdset="0">
         <size>
          <width>20</width>
          <height>40</height>
         </size>
        </property>
       </spacer>
      </item>
     </layout>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>1000</width>
     <height>21</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="toolBar">
   <property name="windowTitle">
    <string>toolBar</string>
   </property>
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <customwidgets>
  <customwidget>
   <class>GroupBoxHFW</class>
   <extends>QGroupBox</extends>
   <header>GroupBoxHFW.h</header>
   <container>1</container>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

GroupBoxHFW.h

#ifndef GROUPBOXHFW_H
#define GROUPBOXHFW_H

#include <QGroupBox>

class GroupBoxHFW : public QGroupBox
{
public:
    GroupBoxHFW(QWidget * parent = 0);
    GroupBoxHFW(const QString & title, QWidget * parent = 0);

    int heightForWidth(int w) const;
    bool hasHeightForWidth() const;
};

#endif // GROUPBOXHFW_H

GroupBoxHFW.cpp

#include "GroupBoxHFW.h"

#include <QDebug>

GroupBoxHFW::GroupBoxHFW(QWidget * parent) : QGroupBox(parent)
{
    QSizePolicy policy(this->sizePolicy());
    policy.setHeightForWidth(true);

    this->setSizePolicy(policy);
}

GroupBoxHFW::GroupBoxHFW(const QString & title, QWidget * parent) : QGroupBox(title, parent)
{
    QSizePolicy policy(this->sizePolicy());
    policy.setHeightForWidth(true);

    this->setSizePolicy(policy);
}


int GroupBoxHFW::heightForWidth(int w) const
{
    qDebug() << "GroupBoxHFW::heightForWidth called";
    return 9.f / 16.f * w;
}

bool GroupBoxHFW::hasHeightForWidth() const
{
    qDebug() << "GroupBoxHFW::hasHeightForWidth called";
    return true;
}

Как видите, я переопределил виртуальные функции int heightForWidth(int w) const а также bool hasHeightForWidth() const, надеясь, что мой QGroupBox изменится автоматически до соотношения сторон 16/9. К сожалению, это не работает. GroupBoxHFW::heightForWidth() вызывается только один раз, когда запускается программа, и она даже не меняет размер виджета.

Вот вывод программы:

GroupBoxHFW::hasHeightForWidth called
horizontalLayout->hasHeightForWidth:  true
GroupBoxHFW::hasHeightForWidth called
GroupBoxHFW::heightForWidth called
GroupBoxHFW::hasHeightForWidth called
GroupBoxHFW::hasHeightForWidth called
GroupBoxHFW::hasHeightForWidth called
GroupBoxHFW::hasHeightForWidth called

Что еще более странно, что ни одна из функций выше (hasHeightForWidth() а также heightForWidth() меня вызывают, когда я изменяю размер окна, в то время как размер QGroupBox изменяется.

В чем дело?

1 ответ

Решение

Ваш подход может сработать, если этот групповой блок находится внутри вертикальной компоновки.

Как следует из названия hasHeightForWidth хорошо определяется, когда высота зависит от ширины (это было разработано для переноса текста), а не наоборот (ваш случай).

Что ты можешь сделать? Попробуйте это (я реализовал нечто подобное для QGraphicsWidget и это работало довольно хорошо)

QSize GroupBoxHFW::sizeHint() const {
    QSize s = size();
    lastHeight = s.height();
    s.setWidth((s.height()*16)/9);
    s.setHeight(QGroupBox::sizeHint().height());
    return s;
}

void GroupBoxHFW::resizeEvent(QResizeEvent * event) {
    QGroupBox::resizeEvent(event);

    if (lastHeight!=height()) {
        updateGeometry(); // it is possible that this call should be scheduled to next iteration of event loop
    }
}

Маленький не по теме:
Если бы я сделал это, я бы попытался реализовать эту функцию с помощью подкласса QLayout а не как подкласс некоторых QWidget, Таким образом, это может быть использовано несколько раз для разных виджетов.

Другие вопросы по тегам