Сохранение соотношения сторон подкласса QWidget при изменении размера
Описание проблемы
По умолчанию при изменении размера виджета, наследуемого от QWidget
, соотношение его сторон не сохраняется на постоянном значении. Но встречаются случаи, когда это недопустимо, поскольку искажается изображение, выводимое виджетом. Возьмем для примера QChartView
, выводящий диаграмму Вольперта-Смита. В простейшем случае данная диаграмма представляет собой окружности постоянного активного сопротивления и дуги постоянного реактивного сопротивления.
Но при изменении размеров окна приложения появляются искажения диаграммы:
Решение
Возможный вариант решения (найден на stackoverflow) заключается в следующем:
- Создать родительский виджет (например,
AspectRatioWidget
подклассаQWidget
) для размещения на нем целевого виджета. - В этом родительском виджете создать
QBoxLayout
. Поместить целевой виджет в центр, а заполнителиQSpacerItem
по бокам. - Затем в этом родительском виджете переопределить метод
QWidget::resizeEvent
, где по мере необходимости изменять направлениеQBoxLayout
и растягивание его элементов.
Ниже приведен пример. Чтобы использовать его, просто создайте экземпляр AspectRatioWidget
и передайте его конструктору указатель на ваш виджет и необходимое соотношение сторон.
Исходный код примера, используемого в данной статье, также доступен на GitHub.
aspectratiowidget.h
#ifndef ASPECTRATIOWIDGET_H
#define ASPECTRATIOWIDGET_H
#include <QWidget>
#include <QBoxLayout>
class AspectRatioWidget : public QWidget
{
public:
AspectRatioWidget(QWidget *widget, float width, float height, QWidget *parent = 0);
protected:
void resizeEvent(QResizeEvent *event) override;
private:
QBoxLayout *layout;
float arWidth; // ширина для задания соотношения сторон
float arHeight; // высота для задания соотношения сторон
};
#endif // ASPECTRATIOWIDGET_H
aspectratiowidget.cpp
#include "aspectratiowidget.h"
#include <QResizeEvent>
//---------------------------------------------------------------------------------------
AspectRatioWidget::AspectRatioWidget(QWidget *widget, float width, float height, QWidget *parent) :
QWidget(parent), arWidth(width), arHeight(height)
{
layout = new QBoxLayout(QBoxLayout::LeftToRight, this);
layout->setContentsMargins(0, 0, 0, 0);
// добавляем сначала заполнитель, затем свой виджет, затем снова заполнитель
layout->addItem(new QSpacerItem(0, 0));
layout->addWidget(widget);
layout->addItem(new QSpacerItem(0, 0));
}
//---------------------------------------------------------------------------------------
void AspectRatioWidget::resizeEvent(QResizeEvent *event)
{
float thisAspectRatio = (float)event->size().width() / event->size().height();
int widgetStretch, outerStretch;
if (thisAspectRatio > (arWidth/arHeight)) // слишком широкий
{
layout->setDirection(QBoxLayout::LeftToRight);
widgetStretch = height() * (arWidth/arHeight); // т.е. ширина виджета
outerStretch = (width() - widgetStretch) / 2 + 0.5;
}
else // слишком высокий
{
layout->setDirection(QBoxLayout::TopToBottom);
widgetStretch = width() * (arHeight/arWidth); // т.е. высота виджета
outerStretch = (height() - widgetStretch) / 2 + 0.5;
}
layout->setStretch(0, outerStretch);
layout->setStretch(1, widgetStretch);
layout->setStretch(2, outerStretch);
}
//---------------------------------------------------------------------------------------
Результат
При размещении диаграммы QChartView
в виджете AspectRatioWidget
искажения, связанные с соотношением сторон, больше не появляются.