I'm trying to create a compound widget similiar to the following:
A Rectangle overlayed with a button that is partially outside the rectangle's bounds.
Here is the code corresponding to that image:
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()
My problem is that the widget's behaviour when resizing suggests that the button is not really "part of" that widget - it is cut-off as if it weren't there:
I tried to overwrite the sizeHint()-method to include the button, but that only solves the problem on startup, I can still resize the window manually to cut the button off again.
What must be changed in order to make this work?
I think I might have found a solution myself by adding the following to the __init__ - method:
self.layout.setContentsMargins(
0,
int(self.btn.height() / 2),
int(self.btn.width() / 2),
0
)
By setting the contentsMargin, the size of the big rectangle doesn't change because it is fixed and the parent widget still covers the space under the button:
I'm not sure if this is the *right way* to do it though ...
Alright, thanks to @musicamante this is the final code:
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()