Qt layouts - Keep widget aspect ratio while resizing [duplicate]

我怕爱的太早我们不能终老 提交于 2019-12-07 08:10:57

问题


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:


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.



来源:https://stackoverflow.com/questions/24264320/qt-layouts-keep-widget-aspect-ratio-while-resizing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!