如何在Qt中保持窗口小部件的纵横比,以及如何将窗口小部件居中?
您不必实现自己的布局管理器。您可以通过继承QWidget
并重新实现来完成。
int QWidget::heightForWidth( int w ) { return w; }
保持正方形。然而,在X11上,heightForWidth()
在顶级窗口上不起作用,因为显然X11协议不支持它。至于居中,您可以将Qt::AlignCenter
作为QBoxLayout :: addWidget()
的第三个参数或QGridLayout :: addWidget()
的第五个参数传递。
注意:在较新版本的Qt中,QWidget不再具有heightForWidth
或widthForHeight
(因此无法重写它们),因此setWidthForHeight(true)
或setHeightForWidth(true)
仅对QGraphicsLayout的后代有效。
正确的答案是创建自定义布局管理器。这可以通过子类化 QLayout 实现。
QLayout
,但是你引用的函数来自于QLayoutItem
,它只是从QWidget
调用相应的函数。那么继承QLayout
能给你什么,而QWidget
本身不能呢? - Marc Mutz - mmutz在resizeEvent()
中调用resize()
从未对我有好处——最好的情况是会导致窗口大小调整两次(就像你一样)引起闪烁,最坏的情况是无限循环。
我认为保持固定宽高比的“正确”方法是创建自定义布局。您只需要覆盖两个方法:QLayoutItem::hasHeightForWidth()
和QLayoutItem::heightForWidth()
。
resizeEvent
函数内调用setMinimumHeight
,有时当我调整大小时,程序会崩溃,我的调用堆栈非常庞大。遗憾的是,我正在考虑创建自己的布局。 - undefinedheightForWidth
和hasHeightForWidth
并没有对我起作用。
- 我简要地研究了实现自定义布局管理器,但是Bleadof的所有链接都已失效,当我找到文档并阅读时,它看起来对于我想要实现的内容来说过于复杂。
最终,我创建了一个自定义小部件,响应resizeEvent
并使用setContentsMargin
设置边距,以使剩余内容区域保持所需的比例。
我发现我还需要在两个方向上将小部件的大小策略设置为QSizePolicy :: Ignored
,以避免由子部件的大小请求导致的奇怪调整大小问题 - 最终结果是我的小部件接受其父级分配给它的任何大小(然后按上面描述的方式设置其边距以保持所需的纵横比在其内容区域中)。
我的代码看起来像这样:
from PySide2.QtWidgets import QWidget, QSizePolicy
class AspectWidget(QWidget):
'''
A widget that maintains its aspect ratio.
'''
def __init__(self, *args, ratio=4/3, **kwargs):
super().__init__(*args, **kwargs)
self.ratio = ratio
self.adjusted_to_size = (-1, -1)
self.setSizePolicy(QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored))
def resizeEvent(self, event):
size = event.size()
if size == self.adjusted_to_size:
# Avoid infinite recursion. I suspect Qt does this for you,
# but it's best to be safe.
return
self.adjusted_to_size = size
full_width = size.width()
full_height = size.height()
width = min(full_width, full_height * self.ratio)
height = min(full_height, full_width / self.ratio)
h_margin = round((full_width - width) / 2)
v_margin = round((full_height - height) / 2)
self.setContentsMargins(h_margin, v_margin, h_margin, v_margin)
class FilterObject:public QObject{
public:
QWidget *target = nullptr;//it holds a pointer to target object
int goalHeight=0;
FilterObject(QObject *parent=nullptr):QObject(parent){}//uses QObject constructor
bool eventFilter(QObject *watched, QEvent *event) override;//and overrides eventFilter function
};
那么eventFilter函数。它的代码应该在FilterObject定义之外进行定义,以避免出现警告。感谢这篇答案。
bool FilterObject::eventFilter(QObject *watched, QEvent *event) {
if(watched!=target){//checks for correct target object.
return false;
}
if(event->type()!=QEvent::Resize){//and correct event
return false;
}
QResizeEvent *resEvent = static_cast<QResizeEvent*>(event);//then sets correct event type
goalHeight = 7*resEvent->size().width()/16;//calculates height, 7/16 of width in my case
if(target->height()!=goalHeight){
target->setFixedHeight(goalHeight);
}
return true;
};
FilterObject *filter = new FilterObject();
QWidget *targetWidget = new QWidget();//let it be target object
filter->target=targetWidget;
targetWidget->installEventFilter(filter);
sizePolicy
,使得hasHeightForWidth() == true
,布局经常会给窗口部件更多的宽度或高度,但这是布局尝试满足约束条件。使用QLayoutItem
解决方案将产生相同的效果,因为它们是等价的(请参阅QWidgetLayoutItem
)。 - Marc Mutz - mmutzwidthForHeight
,怎么办呢?QWidget没有widthForHeight
方法。 - Neptilo