Почему динамическое изменение размера не работает если к родителю подключен Layout?

Мой код

import sys
from PyQt5.QtWidgets import *

class Test(QWidget):
    def __init__(self):
        super().__init__()

        lay = QVBoxLayout(self)
        lay.setContentsMargins(0, 0, 0, 0)

        widget_1 = QWidget()
        lay.addWidget(widget_1)

        lay_2 = QVBoxLayout(widget_1)
        label_1 = QLabel(widget_1)
        label_1.setText("Test - 1")
        label_1.setStyleSheet('background:{};margin:100'.format('yellow'))
        lay_2.addWidget(label_1)

        self.radio = QRadioButton()
        self.radio.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.radio.setStyleSheet('background:{};margin:100'.format('black'))
        lay_2.addWidget(self.radio)

        #face_widget = QWidget(self)
        #face_widget.resize(widget_1.sizeHint().width(), widget_1.sizeHint().height())
        #widget_2 = QWidget(face_widget)

        widget_2 = QWidget(self)
        widget_2.setStyleSheet('background:{}'.format('brown'))
        widget_2.move(10,10)
        #widget_2.resize(65, 55)

        widget_2.raise_()

        lay_3 = QVBoxLayout(widget_2)

        lay_3.setSpacing(0)
        lay_3.setContentsMargins(0, 0, 0, 0)
        label_2 = QLabel(widget_2)
        label_2.setText("Test - 2")
        label_2.setStyleSheet('background:{}'.format('blue'))
        lay_3.addWidget(label_2)

        label_3 = QLabel(widget_2)
        label_3.setText("Test - 3")
        label_3.setStyleSheet('background:{}; padding:10'.format('red'))
        lay_3.addWidget(label_3)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = Test()
    w.show()
    sys.exit(app.exec_())

Я столкнулся с такой проблемой когда к Test(QWidget) подключен lay то все дочерние виджеты которые идут параллельно с lay как widget_2 теряют свою возможность динамически менять размер в зависимости от содержания

Я не знаю с чем это связанно. И не знаю как это исправить

Что я получаю

введите сюда описание изображения

Что мне нужно

введите сюда описание изображения

Мне нужен lay ведь он определяет начальную точку widget_2

Мне нужно что-бы lay и widget_2 могули динамически менять свой размер в зависимости от содержимого

И мне нужно иметь возможность нажать на radio без слежки за его положением в пространстве. потому что если кнопок будет много то писать для каждой

        self.x1r1, self.x2r1, self.y1r1, self.y2r1 = ..., ..., ..., ...     
        self.x1r2, self.x2r2, self.y1r2, self.y2r2 = ..., ..., ..., ...
        self.x1r3, self.x2r3, self.y1r3, self.y2r3 = ..., ..., ..., ...
    def onButtonClicked(self, id):
        print(id)

    def resizeEvent(self, event):                                       
        g1 = self.radio.geometry()
        self.x1r1 = g1.x() 
        self.y1r1 = g1.y()
        self.x2r1 = g1.x() + g1.width()
        self.y2r1 = g1.y() + g1.height()


        super().resizeEvent(event)  

    def mousePressEvent(self, event):     
        x = event.pos().x()
        y = event.pos().y()
        if (self.x1r1 < x < self.x2r1) and (self.y1r1 < y < self.y2r1):
            self.radio.click()

слишком энергозатратно.


Ответы (3 шт):

Автор решения: S. Nick

Уберите self из строки lay = QVBoxLayout(self)

import sys
from PyQt5.QtWidgets import *

class Test(QWidget):
    def __init__(self):
        super().__init__()

        lay = QVBoxLayout()                                             # - self
        lay.setContentsMargins(0, 0, 0, 0)

        widget_1 = QWidget()
        lay.addWidget(widget_1)

        lay_2 = QVBoxLayout(widget_1)
        label_1 = QLabel(widget_1)
        label_1.setText("Test - 1")
        lay_2.addWidget(label_1)

        widget_2 = QWidget(self)
        widget_2.setStyleSheet('background:{}'.format('brown'))
        widget_2.raise_()

        lay_3 = QVBoxLayout(widget_2)

        lay_3.setSpacing(0)
        lay_3.setContentsMargins(0, 0, 0, 0)
        label_2 = QLabel(widget_2)
        label_2.setText("Test - 2")
        label_2.setStyleSheet('background:{}'.format('blue'))
        lay_3.addWidget(label_2)

        label_3 = QLabel(widget_2)
        label_3.setText("Test - 3")
        label_3.setStyleSheet('background:{}; padding: 10px'.format('red'))

        lay_3.addWidget(label_3)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = Test()
    w.resize(640, 570) 
    w.show()
    sys.exit(app.exec_())

введите сюда описание изображения


Update

Добавил widget_2.resize(65, 55), так пойдет ?

import sys
from PyQt5.QtWidgets import *

class Test(QWidget):
    def __init__(self):
        super().__init__()

        lay = QVBoxLayout(self)
        lay.setContentsMargins(0, 0, 0, 0)

        widget_1 = QWidget()
        lay.addWidget(widget_1)

        lay_2 = QVBoxLayout(widget_1)
        label_1 = QLabel(widget_1)
        label_1.setText("Test - 1")
        lay_2.addWidget(label_1)

        widget_2 = QWidget(self)
        widget_2.resize(65, 55)                                                # +++
        widget_2.setStyleSheet('background:{}'.format('brown'))
        widget_2.raise_()

        lay_3 = QVBoxLayout(widget_2)

        lay_3.setSpacing(0)
        lay_3.setContentsMargins(0, 0, 0, 0)
        label_2 = QLabel(widget_2)
        label_2.setText("Test - 2")
        label_2.setStyleSheet('background:{}'.format('blue'))
        lay_3.addWidget(label_2)

        label_3 = QLabel(widget_2)
        label_3.setText("Test - 3")
        label_3.setStyleSheet('background:{}; padding:10'.format('red'))
        lay_3.addWidget(label_3)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = Test()
    w.resize(640, 570) 
    w.show()
    sys.exit(app.exec_())

введите сюда описание изображения


Update 2

import sys
#from PyQt5.QtWidgets import *
from PyQt5.Qt import *

class Test(QWidget):
    def __init__(self):
        super().__init__()

        lay = QVBoxLayout(self)
        lay.setContentsMargins(0, 0, 0, 0)

        widget_1 = QWidget()
        lay.addWidget(widget_1)

        lay_2 = QVBoxLayout(widget_1)
        label_1 = QLabel(widget_1)
        label_1.setText("Test - 1")
        lay_2.addWidget(label_1)

        self.widget_2 = QWidget(self)
#        self.widget_2.setStyleSheet('background:{}'.format('brown'))
#        self.widget_2.raise_()

        lay_H = QHBoxLayout(self.widget_2)                                      # +++ QHBoxLayout
        lay_H.setContentsMargins(0, 0, 0, 0) 

        lay_3 = QVBoxLayout()                                                   # -(widget_2)
        lay_3.setSpacing(0)
        lay_3.setContentsMargins(0, 0, 0, 0)
        label_2 = QLabel(self.widget_2)
        label_2.setText("Test - 2")
        label_2.setStyleSheet('background:{}'.format('blue'))
        lay_3.addWidget(label_2)

        self.label_3 = QLabel(self.widget_2)
        self.label_3.setText("Test - 3")
        self.label_3.setStyleSheet('background:{}; padding:10'.format('red'))
        lay_3.addWidget(self.label_3, stretch=1)                                  # +++


        lay_H.addLayout(lay_3)                                                    # +++
        lay_H.addStretch(1)                                                       # +++

# ++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

        self.i = 0 # Для демонстрации того, что label_3 динамический меняется

    def resizeEvent(self, event): 
        w = self.width()
        self.widget_2.setMinimumSize(w, 55)
        self.widget_2.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)

        # Для демонстрации того, что label_3 динамический меняется
        if self.i < 10:
            self.label_3.setText(self.label_3.text()+'1')
            self.i += 1
        else:
            self.label_3.setText("Test - 3")
            self.i = 0


if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = Test()
    w.resize(640, 570) 
    w.show()
    sys.exit(app.exec_())

введите сюда описание изображения

→ Ссылка
Автор решения: eri

... вчитываюсь в этот бардак и всё ещё более непонятно... куда там столько лэйаутов?

Вот с нуля перерисовал дизайнером:

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(400, 300)
        self.verticalLayout = QtWidgets.QVBoxLayout(Form)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.label = QtWidgets.QLabel(Form)
        self.label.setStyleSheet("background:brown")
        self.label.setObjectName("label")
        self.verticalLayout.addWidget(self.label)
        self.label_3 = QtWidgets.QLabel(Form)
        self.label_3.setStyleSheet("background:red; padding:10")
        self.label_3.setObjectName("label_3")
        self.verticalLayout.addWidget(self.label_3)
        self.label_2 = QtWidgets.QLabel(Form)
        self.label_2.setStyleSheet("background:blue")
        self.label_2.setObjectName("label_2")
        self.verticalLayout.addWidget(self.label_2)
        spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout.addItem(spacerItem)

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.label.setText(_translate("Form", "TextLabel"))
        self.label_3.setText(_translate("Form", "TextLabel"))
        self.label_2.setText(_translate("Form", "TextLabel"))
→ Ссылка
Автор решения: or latym

Ну я нашел решение но это костыль.

import sys
from PyQt5.QtWidgets import *

class Test(QWidget):
    def __init__(self):
        super().__init__()

        widget_block = QWidget(self)

        widget_block.setStyleSheet('background:{};'.format('yellow'))

        lay_2 = QVBoxLayout(widget_block)

        lay_2.setSpacing(0)
        lay_2.setContentsMargins(0, 0, 0, 0)

        label_1 = QLabel(widget_block)
        label_1.setText("Test - 1")
        label_1.setStyleSheet('background:{};margin:100'.format('red'))
        lay_2.addWidget(label_1)

        self.radio = QRadioButton(widget_block)
        self.radio.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.radio.setStyleSheet('background:{};margin:100'.format('black'))
        lay_2.addWidget(self.radio)

        self.resize(widget_block.sizeHint().width(), widget_block.sizeHint().height())
        widget_2 = QWidget(self)

        widget_2.setStyleSheet('background:{}'.format('brown'))
        widget_2.move(10,10)

        widget_2.raise_()

        lay_3 = QVBoxLayout(widget_2)

        lay_3.setSpacing(0)
        lay_3.setContentsMargins(0, 0, 0, 0)
        label_2 = QLabel(widget_2)
        label_2.setText("Test - 2")
        label_2.setStyleSheet('background:{}'.format('blue'))
        lay_3.addWidget(label_2)

        label_3 = QLabel(widget_2)
        label_3.setText("Test - 3")
        label_3.setStyleSheet('background:{}; padding:10'.format('red'))
        lay_3.addWidget(label_3)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = Test()
    w.show()
    sys.exit(app.exec_())
→ Ссылка