在调整大小期间保持子类 QWidget 的纵横比

Posted

技术标签:

【中文标题】在调整大小期间保持子类 QWidget 的纵横比【英文标题】:Keeping the aspect ratio of a sub-classed QWidget during resize 【发布时间】:2015-07-12 09:17:42 【问题描述】:

我正在通过继承 QWidget 类来创建一个新的小部件。我希望能够为这个小部件设置一个比率(对于它的高度和宽度),它将始终保持不变。

为此,我一直使用 Qt5 文档、Google 和 *** 进行搜索。显然,我找到了答案:特别是this one。但是,不幸的是,没有一种是完全有效的:

设置sizeIncrement 完全没有任何作用,即使小部件是一个窗口 我试图重载resizeEvent,但我真的不知道该怎么做......

如果我关注this answer,有两件事:

    如果小部件是***窗口,则根本不保持比例,我可以随意调整它的大小。 如果我把这个小部件放在一个布局中,如果我只是增加窗口的宽度和高度,比例就会保持不变。但是,一旦我将宽度或高度增加很多,小部件就会变平。相反,我希望布局自动调整其大小以保持小部件的比例。

那么,我怎样才能设法保持子类 QWidget 的纵横比?

【问题讨论】:

这是我处理的另一篇文章,效果很好,至少对于QLabels 而言。 ***.com/questions/8211982/… 您是否尝试过重新实现QWidget::heightForWidth()?这允许您指定纵横比。如果这还不够,请创建一个父“虚拟”QWidget 以将您的小部件保存在 3x3 QGridLayout 中,您的小部件位于中间,QSpacerItem 在边缘(参见QGridLayout::addItem())。 QSpacerItem 可以在调整大小时根据需要提供额外的间距(或缩小到 0)。您可能需要使用QGridLayout::setColumnStretch()QGridLayout::setRowStretch() 谢谢你们,您的解决方案有效,但同样的问题仍然存在:如果我尝试仅增加小部件的宽度,则不再保持纵横比。 【参考方案1】:

我已经用 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)

【讨论】:

【参考方案2】:

创建一个用于放置小部件的父小部件(例如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);

【讨论】:

谢谢!该解决方案是唯一对我有用的解决方案,它是 QOpenGLWidget 的子类。我在构造函数中添加了layout->setContentsMargins(0, 0, 0, 0); 以删除边距。 @Anothoy 随机问题,但是有没有一种方法可以在 QHBoxLayout 中使用其中两个 AspectRatioWidgets 并在两侧延伸并仍然让它们填充空间?当我在纵横比小部件的任一侧使用addStretch 时,它会将它们强制为最小尺寸,并且它们不再放大/缩小。

以上是关于在调整大小期间保持子类 QWidget 的纵横比的主要内容,如果未能解决你的问题,请参考以下文章

将具有子元素(包含 imgs/iframes)的元素绝对居中,同时在调整大小时保持它们的纵横比

预览窗格中照片的纵横比,其中高度恒定且仅宽度变化

如何在 Qt 中保持小部件的纵横比?

Javascript库强制HTML元素的纵横比?

在 CSS FlexBox 布局中自动调整图像大小并保持纵横比?

如何按比例调整图像大小/保持纵横比?