部分覆盖其父级范围之外的小部件

Overlay widget partially outside the bounds of it's parent

我正在尝试创建一个类似于以下内容的复合小部件:

一个矩形覆盖了一个部分位于矩形边界之外的按钮。

这是与该图像对应的代码:

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QPoint
from PyQt5.QtGui import QResizeEvent


class MyWidget(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.layout = QHBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.layout)

        self.lbl = QLabel()
        self.lbl.setStyleSheet('background: #EE6622')
        self.lbl.setFixedSize(125, 150)
        self.layout.addWidget(self.lbl)

        self.btn = QPushButton(parent=self)
        self.btn.setStyleSheet('background: #ABCDEF')
        self.btn.setFixedSize(25, 25)

    def resizeEvent(self, event: QResizeEvent) -> None:
        super().resizeEvent(event)
        self.update_btn_pos()

    def update_btn_pos(self):
        pos = (
            self.lbl.pos() +
            QPoint(
                self.lbl.rect().width() - int(self.btn.width() / 2),
                -int(self.btn.height() / 2))
        )
        self.btn.move(pos)


if __name__ == "__main__":
    a = QApplication(sys.argv)
    window = MyWidget()
    window.show()
    a.exec()

我的问题是小部件在调整大小时的行为表明该按钮实际上不是 “该小部件的一部分” - 它被截断了,就好像它不存在一样:

我试图覆盖 sizeHint() 方法以包含按钮,但这只能解决启动时的问题,我仍然可以手动调整 window 的大小再次切断按钮。

为了使这项工作必须改变什么?

在绘制事件小部件上绘制自身,并且他的所有子项都被裁剪到他的范围内。您可以尝试将按钮父级设置为 MyWidget 的父级,但您仍然会遇到按钮阻塞某些其他小部件的一部分或剪裁 window 的客户区的问题。

另一方面,在父窗口小部件内的悬停按钮和突出的悬停按钮之间并没有太大区别,与其他小部件混淆。

我想我可能已经通过将以下内容添加到 __init__ - 方法中找到了自己的解决方案:

self.layout.setContentsMargins(
    0, 
    int(self.btn.height() / 2),
    int(self.btn.width() / 2), 
    0
)

通过设置 contentsMargin,大矩形的大小不会改变,因为它是固定的,父控件仍然覆盖按钮下方的 space:

虽然我不确定这是否是*正确的方法*...


好的,感谢 @musicamante 这是最终代码:

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QResizeEvent


class MyWidget(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.layout = QHBoxLayout()
        self.setLayout(self.layout)

        self.lbl = QLabel()
        self.lbl.setStyleSheet('background: #EE6622')
        self.lbl.setFixedSize(125, 150)
        self.layout.addWidget(self.lbl)

        self.btn = QPushButton(parent=self)
        self.btn.setStyleSheet('background: #ABCDEF')
        self.btn.setFixedSize(25, 25)

        # set contents margin of layout to half the button's size
        self.layout.setContentsMargins(
            *([int(self.btn.height() / 2), int(self.btn.width() / 2)]*2)
        )

    def resizeEvent(self, event: QResizeEvent) -> None:
        super().resizeEvent(event)
        self.update_btn_pos()

    def update_btn_pos(self):
        rect = self.btn.rect()
        rect.moveCenter(self.lbl.geometry().topRight())
        self.btn.move(rect.topLeft())


if __name__ == "__main__":
    a = QApplication(sys.argv)
    window = MyWidget()
    window.show()
    a.exec()

结果: