部分覆盖在其父级边界之外的小部件

问题描述

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

My compound widget

一个被按钮覆盖的矩形,该按钮部分超出了矩形的边界。

这是该图像对应的代码

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)
        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()

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

Widget when resized

我尝试覆盖 sizeHint() 方法以包含按钮,但这只能解决启动时的问题,我仍然可以手动调整窗口大小以再次关闭按钮。 >

为了使这项工作能够正常工作,必须进行哪些更改?

解决方法

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

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

通过设置contentsMargin,大​​矩形的大小不会改变,因为它是固定的,父widget仍然覆盖按钮下的空间:

Widget respecting the button's 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()

结果:
Widget with padding at all sides

,

在绘制事件小部件上绘制自身,并且他的所有孩子都被限制在他的边界上。您可以尝试将按钮父级设置为 pred_prob = model.predict(X_test) # calculate prediction probabilities pred_class = np.where(pred_prob >0.5,"Yes","No") #for binary(Yes/No) category predictions = pd.DataFrame(pred_class,columns=['Prediction']) my_new_df = pd.concat([my_old_df,predictions],axis =1) 的父级,但您仍然会遇到按钮阻塞某些其他小部件的一部分或在窗口的客户区上被剪裁的问题。

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