在调整大小时保持子类 QWidget 的纵横比
Keeping the aspect ratio of a sub-classed QWidget during resize
我正在通过子classQWidget class 创建一个新的小部件。我希望能够为这个小部件设置一个比率(针对其高度和宽度),该比率将始终保持不变。
为此,我一直在使用 Qt5 文档、Google 和 Whosebug 进行搜索。显然,我找到了答案:特别是 this one。但是,不幸的是,没有一个是完全有效的:
- 设置
sizeIncrement
完全没有任何作用,即使小部件是 window
- 我试图重载 resizeEvent,但我真的不知道该怎么做...
如果我遵循this answer,两件事:
- 如果小部件是顶级window,则根本不会保持比例,我可以根据需要调整它的大小。
- 如果我将此小部件放置在布局中,如果我只是增加 window 的宽度和高度,比例将保持不变。但是,一旦我将宽度或高度增加很多,小部件就会变平。相反,我希望布局自动调整其大小以保持小部件的比例。
那么,我怎样才能保持子classed QWidget 的纵横比?
创建一个用于放置您的小部件的父小部件(例如,AspectRatioWidget
)。对于父部件,子类化 QWidget 并给它一个 QBoxLayout。将您的小部件放在中心,并将 QSpacerItems 放在两侧。然后在父部件的 QWidget::resizeEvent
中调整方向并根据需要拉伸。我在下面提供了一个例子。要使用,只需创建一个 AspectRatioWidget
的实例并将构造函数传递给您的小部件的指针和所需的纵横比。
// header
class AspectRatioWidget : public QWidget
{
public:
AspectRatioWidget(QWidget *widget, float width, float height, QWidget *parent = 0);
void resizeEvent(QResizeEvent *event);
private:
QBoxLayout *layout;
float arWidth; // aspect ratio width
float arHeight; // aspect ratio height
};
// cpp
AspectRatioWidget::AspectRatioWidget(QWidget *widget, float width, float height, QWidget *parent) :
QWidget(parent), arWidth(width), arHeight(height)
{
layout = new QBoxLayout(QBoxLayout::LeftToRight, this);
// add spacer, then your widget, then spacer
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)) // too wide
{
layout->setDirection(QBoxLayout::LeftToRight);
widgetStretch = height() * (arWidth/arHeight); // i.e., my width
outerStretch = (width() - widgetStretch) / 2 + 0.5;
}
else // too tall
{
layout->setDirection(QBoxLayout::TopToBottom);
widgetStretch = width() * (arHeight/arWidth); // i.e., my height
outerStretch = (height() - widgetStretch) / 2 + 0.5;
}
layout->setStretch(0, outerStretch);
layout->setStretch(1, widgetStretch);
layout->setStretch(2, outerStretch);
}
我已经在 Python/PySide2 中重写了 Anthony 的代码:
from PySide2.QtWidgets import QBoxLayout, QSpacerItem, QWidget
class AspectRatioWidget(QWidget):
def __init__(self, widget, parent):
super().__init__(parent)
self.aspect_ratio = widget.size().width() / widget.size().height()
self.setLayout(QBoxLayout(QBoxLayout.LeftToRight, self))
# add spacer, then widget, then spacer
self.layout().addItem(QSpacerItem(0, 0))
self.layout().addWidget(widget)
self.layout().addItem(QSpacerItem(0, 0))
def resizeEvent(self, e):
w = e.size().width()
h = e.size().height()
if w / h > self.aspect_ratio: # too wide
self.layout().setDirection(QBoxLayout.LeftToRight)
widget_stretch = h * self.aspect_ratio
outer_stretch = (w - widget_stretch) / 2 + 0.5
else: # too tall
self.layout().setDirection(QBoxLayout.TopToBottom)
widget_stretch = w / self.aspect_ratio
outer_stretch = (h - widget_stretch) / 2 + 0.5
self.layout().setStretch(0, outer_stretch)
self.layout().setStretch(1, widget_stretch)
self.layout().setStretch(2, outer_stretch)
我正在通过子classQWidget class 创建一个新的小部件。我希望能够为这个小部件设置一个比率(针对其高度和宽度),该比率将始终保持不变。
为此,我一直在使用 Qt5 文档、Google 和 Whosebug 进行搜索。显然,我找到了答案:特别是 this one。但是,不幸的是,没有一个是完全有效的:
- 设置
sizeIncrement
完全没有任何作用,即使小部件是 window - 我试图重载 resizeEvent,但我真的不知道该怎么做...
如果我遵循this answer,两件事:
- 如果小部件是顶级window,则根本不会保持比例,我可以根据需要调整它的大小。
- 如果我将此小部件放置在布局中,如果我只是增加 window 的宽度和高度,比例将保持不变。但是,一旦我将宽度或高度增加很多,小部件就会变平。相反,我希望布局自动调整其大小以保持小部件的比例。
那么,我怎样才能保持子classed QWidget 的纵横比?
创建一个用于放置您的小部件的父小部件(例如,AspectRatioWidget
)。对于父部件,子类化 QWidget 并给它一个 QBoxLayout。将您的小部件放在中心,并将 QSpacerItems 放在两侧。然后在父部件的 QWidget::resizeEvent
中调整方向并根据需要拉伸。我在下面提供了一个例子。要使用,只需创建一个 AspectRatioWidget
的实例并将构造函数传递给您的小部件的指针和所需的纵横比。
// header
class AspectRatioWidget : public QWidget
{
public:
AspectRatioWidget(QWidget *widget, float width, float height, QWidget *parent = 0);
void resizeEvent(QResizeEvent *event);
private:
QBoxLayout *layout;
float arWidth; // aspect ratio width
float arHeight; // aspect ratio height
};
// cpp
AspectRatioWidget::AspectRatioWidget(QWidget *widget, float width, float height, QWidget *parent) :
QWidget(parent), arWidth(width), arHeight(height)
{
layout = new QBoxLayout(QBoxLayout::LeftToRight, this);
// add spacer, then your widget, then spacer
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)) // too wide
{
layout->setDirection(QBoxLayout::LeftToRight);
widgetStretch = height() * (arWidth/arHeight); // i.e., my width
outerStretch = (width() - widgetStretch) / 2 + 0.5;
}
else // too tall
{
layout->setDirection(QBoxLayout::TopToBottom);
widgetStretch = width() * (arHeight/arWidth); // i.e., my height
outerStretch = (height() - widgetStretch) / 2 + 0.5;
}
layout->setStretch(0, outerStretch);
layout->setStretch(1, widgetStretch);
layout->setStretch(2, outerStretch);
}
我已经在 Python/PySide2 中重写了 Anthony 的代码:
from PySide2.QtWidgets import QBoxLayout, QSpacerItem, QWidget
class AspectRatioWidget(QWidget):
def __init__(self, widget, parent):
super().__init__(parent)
self.aspect_ratio = widget.size().width() / widget.size().height()
self.setLayout(QBoxLayout(QBoxLayout.LeftToRight, self))
# add spacer, then widget, then spacer
self.layout().addItem(QSpacerItem(0, 0))
self.layout().addWidget(widget)
self.layout().addItem(QSpacerItem(0, 0))
def resizeEvent(self, e):
w = e.size().width()
h = e.size().height()
if w / h > self.aspect_ratio: # too wide
self.layout().setDirection(QBoxLayout.LeftToRight)
widget_stretch = h * self.aspect_ratio
outer_stretch = (w - widget_stretch) / 2 + 0.5
else: # too tall
self.layout().setDirection(QBoxLayout.TopToBottom)
widget_stretch = w / self.aspect_ratio
outer_stretch = (h - widget_stretch) / 2 + 0.5
self.layout().setStretch(0, outer_stretch)
self.layout().setStretch(1, widget_stretch)
self.layout().setStretch(2, outer_stretch)