Showing pre-created UI components
Unsolved
Qt for Python
-
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 2I 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()