Qt FlowLayout示例-布局更改时如何获取sizeHint?

时间:2019-04-24 00:05:46

标签: python pyside2 flowlayout qlayout

我想在布局中排列一堆QPushButton,以便它们将水平包裹(如文本)。我正在尝试在PySide2中使用Qt示例FlowLayout。

我已经发布了一个简单的示例revision 2 here

(这是基于官方示例here的原因,这就是为什么我如此困扰它无法正常工作的原因。)

具体地说,当窗口足够大时,它会很好地工作:

window works well when large wide window works well when large tall

但不会阻止窗口缩小,而VBoxLayout或GridLayout会:

window can be resized too small

我认为最小尺寸应取决于当前宽度。这应该是最小尺寸:

wide minimum size

这也应该如此:

narrow minimum size is tall

如何获取布局以防止其父视图缩小到看不到其内容?

sizeHint()和minimumSize()始终返回单个项目的大小,我认为这是问题所在。但是,如果我重写它们以考虑当前布局宽度下的所有项目,则没关系,因为在我创建和填充布局时,这两项仅被调用一次。

到目前为止,我最好的想法是从heightForWidth()调用update(),大致是这样:

def heightForWidth(self, width):
    oldWidth = self.geometry().width() - 2 * self.contentsMargins().top()
    oldHeight = self.doLayout(QtCore.QRect(0, 0, oldWidth, 0), True)
    height = self.doLayout(QtCore.QRect(0, 0, width, 0), True)
    print 'heightForWidth', width, oldWidth, height, oldHeight
    if height != oldHeight:
        self.update()
    return height
更改了minimumSize和doLayout的

完整示例为revision 3。  有时可以使用,但是有几个问题:

  1. 首次创建布局时,会不断调用update()。我认为对update()的调用会触发对heightForWidth()的调用,由于某种原因,传入的宽度不接近我计算的“ oldWidth”,直到调整窗口大小为止,即使只有一个像素也是如此。

  2. 调整窗口大小后,对heightForWidth()的调用将完全停止,并停止调用minimumSize(),并且我无法再将窗口的大小调整为小于上一次计算的大小。我不知道为什么。

  3. (不那么重要)self.geometry().width() - 2 * self.contentsMargins().top()不会返回最后传递给heightForWidth的宽度(即使当上/下/左/右边界相同时),尽管我从其他代码中这个例子。这通常无关紧要,但是在某些宽度下会引起对update()的大量调用

我想我做错了。可以做对吗?

2 个答案:

答案 0 :(得分:0)

您只能修改setGeometry()minimumSize()函数。我使用C ++工作,但是很容易将其修改为Python。

首先,我更改了minimumSize()返回的QSize以考虑布局的当前大小,然后设置返回的QSize的高度。然后,我在update()中调用setGeometry(),以强制布局重新检查sizeHint()。下面是代码示例。

QSize FlowLayout::minimumSize() const
{
    QSize size;
    for (const QLayoutItem *item : qAsConst(itemList))
    {
        size = size.expandedTo(item->minimumSize());
    }
    const QMargins margins = contentsMargins();
    size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom());

    // ADDED CODE **************************************
    auto layoutSize = this->contentsRect();
    size.setHeight(heightForWidth(layoutSize.width()));
    // *************************************************

    return size;
}

void FlowLayout::setGeometry(const QRect &rect)
{
    // ADDED CODE ************************************
    update();
    // ***********************************************
    QLayout::setGeometry(rect);
    doLayout(rect, false);
}

希望这会有所帮助。

答案 1 :(得分:0)

我现在已经将原始/官方示例移植到PySide2,并且无需更改即可工作。我不确定是什么原因阻止了它的工作。