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

Python 自定义布局管理器中缺少子窗口小部件的调整大小事件,python,qt,pyqt,pyqt5,qt5,Python,Qt,Pyqt,Pyqt5,Qt5,在PyQt5中,我尝试使用一个()来缩放标签图像。当使用普通的BoxLayout进行测试时,缩放图像本身的工作方式与预期的一样,并在执行缩放时实现方法resizeEvent(self,evt) 但是,当我尝试将其用于自定义FlowLayout时,标签图像在调整外部容器大小时不再接收调整大小事件(侦听器在小部件创建时仅执行一次),因此图像不会缩放。这里可以看到问题: 收缩后,将剪切图像: 为什么图像不再接收resizeEvent 布局管理器的代码来自: #来自Qt文档并由jonB修改/改编的代

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

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

收缩后,将剪切图像:

为什么图像不再接收resizeEvent

布局管理器的代码来自:

#来自Qt文档并由jonB修改/改编的代码
类流布局(QLayout):
def uu init uuu(self,parent:QWidget=None,margin:int=-1,hSpacing:int=-1,vSpacing:int=-1):
super()。\uuuu init\uuuu(父级)
self.itemList=list()
self.m_hSpace=hSpacing
self.m_vSpace=vSpacing
self.setContentsMargins(边距、边距、边距、边距)
定义(自我):
#为保持一致性而复制,不确定是否需要或是否调用过
item=self.takeAt(0)
而项目:
item=self.takeAt(0)
def附加项(自身,项目:QLayoutItem):
self.itemList.append(项)
def水平间距(自)->int:
如果self.m_hSpace>=0:
返回self.m_hSpace
其他:
返回self.smartSpacing(QStyle.PM_layouuthorizontalspacking)
def垂直间距(自)->int:
如果self.m_vSpace>=0:
返回self.m_vSpace
其他:
返回self.smartSpacing(QStyle.PM\U布局垂直间距)
def计数(自身)->int:
返回len(self.itemList)
def itemAt(self,index:int)->typing.Union[QLayoutItem,None]:
如果0正在键入.Union[QLayoutItem,无]:
如果0 Qt.方向:
返回Qt.方向(Qt.方向(0))
def hasHeightForWidth(自)->bool:
返回真值
def heightForWidth(self,width:int)->int:
高度=self.doLayout(QRect(0,0,宽度,0),真)
返回高度
def setGeometry(自身、直肠:QRect)->无:
super().setGeometry(rect)
自我分配(正确,错误)
def sizeHint(自身)->QSize:
返回self.minimumSize()
def最小尺寸(自身)->QSize:
size=QSize()
对于self.itemList中的项目:
size=size.expandedTo(item.minimumSize())
页边距=self.contentsMargins()
size+=QSize(margins.left()+margins.right()、margins.top()+margins.bottom())
返回大小
def smartSpacing(self,pm:QStyle.PixelMetric)->int:
parent=self.parent()
如果不是家长:
返回-1
elif parent.isWidgetType():
返回parent.style().pixelMetric(pm,None,parent)
其他:
返回parent.spating()
def-doLayout(self、rect:QRect、testOnly:bool)->int:
左、上、右、下=self.getContentsMargins()
effectiveRect=调整后的直线(+左、+上、-右、-下)
x=effectivelect.x()
y=有效的影响因素。y()
线宽=0
对于self.itemList中的项目:
wid=item.widget()
spaceX=self.horizontalSpacing()
如果spaceX==-1:
spaceX=wid.style().layoutSpacing(QSizePolicy.butdown、QSizePolicy.butdown、Qt.Horizontal)
spaceY=self.verticalSpacing()
如果spaceY==-1:
spaceY=wid.style().layoutSpacing(QSizePolicy.butdown、QSizePolicy.butdown、Qt.Vertical)
nextX=x+item.sizeHint().width()+spaceX
如果nextX-spaceX>effectiveRect.right()且线宽>0:
x=effectivelect.x()
y=y+线宽+空格y
nextX=x+item.sizeHint().width()+spaceX
线宽=0
如果不只是测试:
item.setGeometry(QRect(QPoint(x,y),item.sizeHint())
x=nextX
lineHeight=max(lineHeight,item.sizeHint().height())
返回y+线宽-矩形y()+底部

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 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
def sizeHint(self):
    return QtCore.QSize(preferredWidth, preferredHeight)