4

I want to keep an aspect ratio of 16/9 on a QGroupBox (the one on the left on the screenshot below). For the tests I made a simple program with 4 groupboxes in a vertical layout, all in an horizontal layout:

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;
}

As you can see, I reimplemented the virtual functions int heightForWidth(int w) const and bool hasHeightForWidth() const, hoping my QGroupBox would resize automatically to a 16/9 aspect ratio. Unfortunately, it doesn't work. GroupBoxHFW::heightForWidth() is called only once when the program starts and it doesn't even resize the widget.

Here is the output of the program:

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

What's even weirder is that none of the functions above (hasHeightForWidth() and heightForWidth() get called when I resize the window, while the QGroupBox is resized.

What's wrong?

1

1 Answer 1

2

Your approach could work if this group box was inside vertical layout.

As name says hasHeightForWidth is well defined when height depends on width (this was designed for text wrapping), not another way around (your case).

What you can do? Try this (I've implemented something similar for QGraphicsWidget and it was working quite well):

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
    }
}

Small off topic:
If I would do that I would try implement this functionality by subclass a QLayout and not as a subclass of some QWidget. This way this it could be used multiple times for different widgets.

2
  • It doesn't work either. Note: you forgot that sizeHint() is const, you can't assign a member variable (lastHeight) inside this function. I removed the condition in resizeEvent() to fix the problem.
    – GuiTeK
    Commented Jun 17, 2014 at 14:53
  • 1
    add keyword mutable for this field. Condition in resizeEvent is a must, to prevent infinite loop.
    – Marek R
    Commented Jun 17, 2014 at 15:15

Not the answer you're looking for? Browse other questions tagged or ask your own question.