Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Showing pre-created UI components



  • I am not sure if this is the correct way to utilize Qt widgets

    I am writing an application that show 3 possible set of UI

    (1) None (blank)
    (2) Option 1
    (3) Option 2

    I am thinking of creating the UI widgets for each of the options in the constructor and than through some Qt mechanism show the appropriate one depending on option chosen?

    Is this counter to Qt design philosophy or should I write the code to recreate the entire UI widget tree for each options every time ?

    import sys
    from PySide2 import QtWidgets, QtCore
    
    
    class Example(QtWidgets.QWidget):
    
        def __init__(self):
            super(Example, self).__init__()
    
            self.initUI()
    
        def initUI(self):
    
            self.option1Widget = self.initOption1_UI()
            self.option2Widget = self.initOption2_UI()
    
            self.hbox = QtWidgets.QHBoxLayout(self)
            self.vbox = QtWidgets.QVBoxLayout()
            self.none_button = QtWidgets.QRadioButton('None')
            self.option1_button = QtWidgets.QRadioButton('Option 1')
            self.option2_button = QtWidgets.QRadioButton('Option 2')
            self.none_button.clicked.connect(self.handleNone)
            self.option1_button.clicked.connect(self.handleOption1)
            self.option2_button.clicked.connect(self.handleOption2)
            self.vbox.addWidget(self.none_button)
            self.vbox.addWidget(self.option1_button)
            self.vbox.addWidget(self.option2_button)
    
            self.hbox.addLayout(self.vbox)
            self.placeHolderWidget = QtWidgets.QWidget()
            self.hbox.addWidget(self.placeHolderWidget)
    
            self.setGeometry(300, 300, 300, 150)
            self.setWindowTitle('Swap')
    
        def initOption1_UI(self):
            result = QtWidgets.QWidget()
            b1 = QtWidgets.QLabel('Option1', result)
    
            return result
        
        def initOption2_UI(self):
            result = QtWidgets.QWidget()
            b2 = QtWidgets.QLabel('Option2', result)
    
            return result
    
        def handleNone(self):
            print('None')
    
        def handleOption1(self):
            print('Option 1')
            self.placeHolderWidget = self.option1Widget
            # self.placeHolderWidget.setParent(self)
            
        def handleOption2(self):
            print('Option 2')
            self.placeHolderWidget = self.option2Widget
    
    
    def main():
    
        app = QtWidgets.QApplication(sys.argv)
        ex = Example()
        ex.show()
        sys.exit(app.exec_())
    
    
    if __name__ == '__main__':
        main()
    


  • I came up with this approach but not sure if I will create memory/resource leak

        def handleNone(self):
            print('None')
            self.hbox.replaceWidget(self.hbox.itemAt(1).widget(),self.placeHolderWidget)
            self.placeHolderWidget.setVisible(True)
            self.option1Widget.setVisible(False)
            self.option2Widget.setVisible(False)
    
        def handleOption1(self):
            print('Option 1')
            self.hbox.itemAt(1).widget().setVisible(False)
            self.hbox.replaceWidget(self.hbox.itemAt(1).widget(),self.option1Widget)
            self.option1Widget.setVisible(True)
    
    
        def handleOption2(self):
            print('Option 2')
            self.hbox.itemAt(1).widget().setVisible(False)
            self.hbox.replaceWidget(self.hbox.itemAt(1).widget(),self.option2Widget)
            self.option2Widget.setVisible(True)
    


  • A more elegant solution is to use a QStackedWidget with a QButtonGroup:

    from PySide2.QtCore import Qt
    from PySide2.QtWidgets import (
        QApplication,
        QButtonGroup,
        QLabel,
        QRadioButton,
        QStackedWidget,
        QVBoxLayout,
        QWidget,
    )
    
    
    class Widget(QWidget):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            lay = QVBoxLayout(self)
            button_group = QButtonGroup(self)
            button_group.idClicked.connect(self.handle_clicked)
    
            for i, text in enumerate(("None", "Option 1", "Option 2")):
                button = QRadioButton(text)
                lay.addWidget(button)
                button_group.addButton(button, i)
    
            self.option1_widget = QLabel("option1", alignment=Qt.AlignCenter)
            self.option2_widget = QLabel("option2", alignment=Qt.AlignCenter)
    
            self.stacked_widget = QStackedWidget()
            self.stacked_widget.addWidget(self.option1_widget)
            self.stacked_widget.addWidget(self.option2_widget)
            lay.addWidget(self.stacked_widget)
            lay.addStretch()
    
            button_group.button(0).click()
    
        def handle_clicked(self, i):
            if i == 0:
                self.stacked_widget.hide()
            elif i == 1:
                self.stacked_widget.show()
                self.stacked_widget.setCurrentWidget(self.option1_widget)
            elif i == 2:
                self.stacked_widget.show()
                self.stacked_widget.setCurrentWidget(self.option2_widget)
    
    
    def main():
        import sys
    
        app = QApplication(sys.argv)
        w = Widget()
        w.resize(640, 480)
        w.show()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    


  • How about QStackedWidget with QComboBox instead of QButtonGroup ? Is that fine too ?



  • @nicholas_yue The logic is similar

    from PySide2.QtCore import Qt
    from PySide2.QtWidgets import (
        QApplication,
        QComboBox,
        QLabel,
        QStackedWidget,
        QVBoxLayout,
        QWidget,
    )
    
    
    class Widget(QWidget):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            combo = QComboBox()
            combo.currentIndexChanged.connect(self.handle_current_index)
    
            self.option1_widget = QLabel("option1", alignment=Qt.AlignCenter)
            self.option2_widget = QLabel("option2", alignment=Qt.AlignCenter)
    
            self.stacked_widget = QStackedWidget()
            self.stacked_widget.addWidget(self.option1_widget)
            self.stacked_widget.addWidget(self.option2_widget)
    
            lay = QVBoxLayout(self)
            lay.addWidget(combo)
            lay.addWidget(self.stacked_widget)
            lay.addStretch()
    
            combo.addItems(("None", "Option 1", "Option 2"))
            combo.setCurrentIndex(0)
    
        def handle_current_index(self, i):
            if i == 0:
                self.stacked_widget.hide()
            elif i == 1:
                self.stacked_widget.show()
                self.stacked_widget.setCurrentWidget(self.option1_widget)
            elif i == 2:
                self.stacked_widget.show()
                self.stacked_widget.setCurrentWidget(self.option2_widget)
    
    
    def main():
        import sys
    
        app = QApplication(sys.argv)
        w = Widget()
        w.resize(640, 480)
        w.show()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

Log in to reply