自定义布局管理器中缺少子窗口小部件的调整大小事件

2024-05-18 12:33:53 发布

您现在位置:Python中文网/ 问答频道 /正文

在PyQt5中,我尝试使用(FlowLayout)来缩放标签图像。当使用普通的BoxLayout进行测试时,缩放图像本身的工作方式与预期的一样,并在执行缩放时实现方法resizeEvent(self, evt)

但是,当我尝试将其用于自定义FlowLayout时,标签图像在调整外部容器大小时不再接收调整大小事件(侦听器在小部件创建时仅执行一次),因此图像不会缩放。这里可以看到问题:

enter image description here

收缩后,将剪切图像:

enter image description here

为什么图像不再接收resizeEvent

布局管理器的代码来自here

# Code from Qt Docs and modified/adapted by jonB

class FlowLayout(QLayout):
    def __init__(self, parent: QWidget=None, margin: int=-1, hSpacing: int=-1, vSpacing: int=-1):
        super().__init__(parent)

        self.itemList = list()
        self.m_hSpace = hSpacing
        self.m_vSpace = vSpacing

        self.setContentsMargins(margin, margin, margin, margin)

    def __del__(self):
        # copied for consistency, not sure this is needed or ever called
        item = self.takeAt(0)
        while item:
            item = self.takeAt(0)

    def addItem(self, item: QLayoutItem):
        self.itemList.append(item)

    def horizontalSpacing(self) -> int:
        if self.m_hSpace >= 0:
            return self.m_hSpace
        else:
            return self.smartSpacing(QStyle.PM_LayoutHorizontalSpacing)

    def verticalSpacing(self) -> int:
        if self.m_vSpace >= 0:
            return self.m_vSpace
        else:
            return self.smartSpacing(QStyle.PM_LayoutVerticalSpacing)

    def count(self) -> int:
        return len(self.itemList)

    def itemAt(self, index: int) -> typing.Union[QLayoutItem, None]:
        if 0 <= index < len(self.itemList):
            return self.itemList[index]
        else:
            return None

    def takeAt(self, index: int) -> typing.Union[QLayoutItem, None]:
        if 0 <= index < len(self.itemList):
            return self.itemList.pop(index)
        else:
            return None

    def expandingDirections(self) -> Qt.Orientations:
        return Qt.Orientations(Qt.Orientation(0))

    def hasHeightForWidth(self) -> bool:
        return True

    def heightForWidth(self, width: int) -> int:
        height = self.doLayout(QRect(0, 0, width, 0), True)
        return height

    def setGeometry(self, rect: QRect) -> None:
        super().setGeometry(rect)
        self.doLayout(rect, False)

    def sizeHint(self) -> QSize:
        return self.minimumSize()

    def minimumSize(self) -> QSize:
        size = QSize()
        for item in self.itemList:
            size = size.expandedTo(item.minimumSize())

        margins = self.contentsMargins()
        size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom())
        return size

    def smartSpacing(self, pm: QStyle.PixelMetric) -> int:
        parent = self.parent()
        if not parent:
            return -1
        elif parent.isWidgetType():
            return parent.style().pixelMetric(pm, None, parent)
        else:
            return parent.spacing()

    def doLayout(self, rect: QRect, testOnly: bool) -> int:
        left, top, right, bottom = self.getContentsMargins()
        effectiveRect = rect.adjusted(+left, +top, -right, -bottom)
        x = effectiveRect.x()
        y = effectiveRect.y()
        lineHeight = 0

        for item in self.itemList:
            wid = item.widget()
            spaceX = self.horizontalSpacing()
            if spaceX == -1:
                spaceX = wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Horizontal)
            spaceY = self.verticalSpacing()
            if spaceY == -1:
                spaceY = wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Vertical)

            nextX = x + item.sizeHint().width() + spaceX
            if nextX - spaceX > effectiveRect.right() and lineHeight > 0:
                x = effectiveRect.x()
                y = y + lineHeight + spaceY
                nextX = x + item.sizeHint().width() + spaceX
                lineHeight = 0

            if not testOnly:
                item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))

            x = nextX
            lineHeight = max(lineHeight, item.sizeHint().height())

        return y + lineHeight - rect.y() + bottom

Tags: rect图像selfnoneindexreturnifdef
1条回答
网友
1楼 · 发布于 2024-05-18 12:33:53

resizeEvent仅在调整标签大小时才对其调用。布局管理器FlowLayout从未调整其子级的大小。请参见doLayout中的以下行

item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))

在这里,子项的新大小被设置为item.sizeHint(),默认情况下,它是item的当前大小(可以通过覆盖小部件类中的sizeHint来更改标签)

如果容器的宽度足以显示至少一个项目,则以下更新的doLayout将使用sizeHint()。否则,将调整项目的大小(保持纵横比),以便在一列中完全显示其宽度。此代码仅用于说明。您仍然需要进行更精细的调整,以将间距和边框合并到调整大小计算中。更改用######…标记

def doLayout(self, rect: QRect, testOnly: bool) -> int:
    left, top, right, bottom = self.getContentsMargins()
    effectiveRect = rect.adjusted(+left, +top, -right, -bottom)
    x = effectiveRect.x()
    y = effectiveRect.y()
    lineHeight = 0

    for item in self.itemList:
        ###########################
        itemSize = item.sizeHint()
        itemNewWidth = min(rect.width(), itemSize.width())
        itemSize = QtCore.QSize(itemNewWidth, itemSize.height() * itemNewWidth / itemSize.width())

        wid = item.widget()
        spaceX = self.horizontalSpacing()
        if spaceX == -1:
            spaceX = wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Horizontal)
        spaceY = self.verticalSpacing()
        if spaceY == -1:
            spaceY = wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Vertical)

        nextX = x + item.sizeHint().width() + spaceX
        if nextX - spaceX > effectiveRect.right() and lineHeight > 0:
            x = effectiveRect.x()
            y = y + lineHeight + spaceY
            nextX = x + item.sizeHint().width() + spaceX
            lineHeight = 0

        if not testOnly:
            ###########################
            item.setGeometry(QRect(QPoint(x, y), itemSize))

        x = nextX
        ###########################
        lineHeight = max(lineHeight, itemSize.height())

    return y + lineHeight - rect.y() + bottom

要使此项工作正常,您可能必须重新定义标签的sizeHint()以返回固定大小(而不是当前大小)

def sizeHint(self):
    return QtCore.QSize(preferredWidth, preferredHeight)

Working Layout in action

相关问题 更多 >

    热门问题