Home > Software design >  qt: qlayout do not correctly add widget
qt: qlayout do not correctly add widget

Time:08-09

I want do dynamically change the layout in Qt. For example, I want to change the QHBoxLayout to QVBoxLayout through a button. My test code is:

from PyQt5.QtWidgets import *
import sys

class SubWidget(QWidget):

    def __init__(self):
        super().__init__()
        self.lay = QHBoxLayout()
        self.label1 = QLabel('left')
        self.label2 = QLabel('right')
        self.lay.addWidget(self.label1)
        self.lay.addWidget(self.label2)
        self.setLayout(self.lay)

    def change(self):

        self.lay.removeWidget(self.label1)
        self.lay.removeWidget(self.label2)

        self.lay = QVBoxLayout()
        self.setLayout(self.lay)
        self.lay.addWidget(self.label2)
        self.lay.addWidget(self.label1)

class Widget(QWidget):

    def __init__(self):
        super().__init__()

        lay = QVBoxLayout()

        self.btn = QPushButton('change layout')
        self.btn.clicked.connect(self.btnClick)

        self.subWidget = SubWidget()

        lay.addWidget(self.btn)
        lay.addWidget(self.subWidget)
        self.setLayout(lay)

    def btnClick(self, check=False):
        self.subWidget.change()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    win = Widget()
    win.show()
    app.exec_()

The code output GUI is:

enter image description here

And I hope it change to the following picture after click change layout button:

enter image description here

Any suggestion is appreciated~~~

CodePudding user response:

The point of the solution is

  1. Make sure old layout is deleted, included both python wrapping reference and core Qt object, that's for deleteLater() is used.
  2. Make sure new layout is assigned strictly after old was deleted, that's for need to use destroyed()-switchlayout() signal-slot chain.

I reproduced example with PySide6 (don't forget to switch on your version of PyQt or PySide package):

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

class SubWidget(QWidget):

    def __init__(self):
        super().__init__()
        self.lay = QVBoxLayout()
        self.label1 = QLabel('left')
        self.label2 = QLabel('right')
        self.lay.addWidget(self.label1)
        self.lay.addWidget(self.label2)
        self.setLayout(self.lay)

    def change(self):
        self.lay.removeWidget(self.label1)
        self.lay.removeWidget(self.label2)
        self.lay.deleteLater()
        self.lay.destroyed.connect(self.switchlayout)

    def switchlayout(self):
        # print("***destroyed")
        self.lay = QHBoxLayout()
        self.lay.addWidget(self.label2)
        self.lay.addWidget(self.label1)
        self.setLayout(self.lay)
        self.adjustSize()        

class Widget(QWidget):

    def __init__(self):
        super().__init__()

        lay = QVBoxLayout()

        self.btn = QPushButton('change layout')
        self.btn.clicked.connect(self.btnClick)

        self.subWidget = SubWidget()

        lay.addWidget(self.btn)
        lay.addWidget(self.subWidget)
        self.setLayout(lay)

    def btnClick(self, check=False):
        self.subWidget.change()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    win = Widget()
    win.show()
    app.exec_()
  • Related