Python Forum
[PyQt] Help: Replace widgets in a QFrame on Combobox change
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyQt] Help: Replace widgets in a QFrame on Combobox change
#1
Hi all,

I have the following problem which I do not seem to get solved:
  • My aim is that I want to have a single QFrame in which QWidgets are replaced when I select a different QComboBox entry (Frame2 or Frame3.
  • Clear the widgets in a QFrame when I change the QComboBox entry.

Currently I have the following:
I have two 'permanent' QFrames:
A: A QFrame with a set of Comboboxes of which one connects to a function which displays one of two not permanent QFrames based on the QComboBox entry (selection options in this example are Frame2 and Frame3.
B: A QFrame with a set of buttons (not connected in the below code).

The two other QFrames are frames which should only be there when the respective selection in the Combobox is active.

However, my workaround means that I need to create two QFrames and populate these QFrames which their respective QLabels, QLineEdits for each of the possible QComboBox entries (eg. Frame2 and Frame3). Based on the QComboBox entry, I hide the QFrame that was linked to the 'old' QComboBox entry and show the QFrame that is linked to the 'selected' QComboBox entry. This also means that the QFrames keep existing and with it the content of the QLineEdits etc. will also remain when changing the visibility of the QFrame. So when I return to the QFrame afterwards, the entries still exist.

How can I make sure that, when I change the QComboBox entry from Frame2 to [inline]Frame3[/inline I can rebuild a single QFrame with different widgets so that I only have to use one QFrame to display different layouts. It also needs to clear all the widgets from the old layout, should they still exist.

See below code I have written so far:
import sys
from PySide2.QtWidgets import *
from PySide2.QtGui import *

class Layout(QDialog):
    def __init__(self, parent=None, type='Frame2'):
        self.type = type

        super(Layout, self).__init__(parent)
        self.setFixedWidth(600)
        self.button_frame = QFrame()
        self.A = Button('A')
        self.B = Button('B')
        self.C = Button('C')
        self.D = Button('D')

        self.type_frame = QFrame()
        self.lbl_type = Label('Type', width=168)
        self.lbl_name = Label('Name', width=168)
        self.change_name = Combo()
        self.change_type = Combo()

        self.frame2 = QFrame()
        self.lbl_types = Label('Mixture', width=168)
        self.types = Combo()
        self.types.addItems(['Flower', 'Meat', 'Appels', 'Potatoes'])
        self.tableA = QTableWidget()

        self.frame3 = QFrame()
        self.radio_manual = Radio('Test', 130)
        self.input_manual = LineEdit()
        self.radio_max = Radio('Max input')
        self.radio_min = Radio('Min input')
        self.tableB = QTableWidget()

        self.change_type.addItems(['Frame2', 'Frame3'])
        self.change_type.setEditable(False)

        self.tableA = make_table(["test1", "test2", "test3"], [260, 60, 60], 13)
        self.tableB = make_table([["test1", "test2", "test3"]], [260, 60, 60], 4,
                                 [['A', '[-]'],
                                                      ['B', '[-]'],
                                                      ['C', '[-]'], ['D', '[-]']])
        self.make_edit_buttons_frame()
        self.make_selection_frame()
        self.make_frame2()
        self.make_frame4()
        self.add_signals()

        self.state_types = {'Frame2': self.frame2, 'Frame3': self.frame3}

        self.change_type.setCurrentText(self.type)

        self.make_layout()

    def add_signals(self):
        self.change_type.currentIndexChanged.connect(self.rebuild_layout)


    def make_layout(self):
        col1 = QVBoxLayout()
        col1.addWidget(self.type_frame)

        col1.addWidget(self.state_types.get(self.type))
        col1.addStretch()

        self.layout = QHBoxLayout()
        self.layout.addLayout(col1)
        self.layout.addWidget(self.button_frame)
        self.setLayout(self.layout)
        self.current_type = self.change_type.currentText()

    def rebuild_layout(self):
        old_type = self.current_type
        new_type = self.change_type.currentText()
        old_type = self.state_types[old_type]
        new_type = self.state_types[new_type]

        self.layout.replaceWidget(old_type, new_type)
        old_type.setVisible(False)
        new_type.setVisible(True)
        self.current_type = self.change_type.currentText()

    def make_frame2(self):
        row1 = QHBoxLayout()
        row1.addWidget(self.lbl_types)
        row1.addWidget(self.types)
        row1.addStretch()

        layout = QVBoxLayout()
        layout.setSpacing(3)
        layout.addLayout(row1)
        layout.addWidget(self.tableA)
        self.frame2.setLayout(layout)

    def make_edit_buttons_frame(self):
        layout = QVBoxLayout()
        layout.setSpacing(3)
        layout.addWidget(self.A)
        layout.addWidget(self.B)
        layout.addWidget(self.C)
        layout.addWidget(self.D)
        layout.addStretch()
        self.button_frame.setLayout(layout)

    def make_selection_frame(self):
        layout = QVBoxLayout()
        layout.setSpacing(3)
        row1 = QHBoxLayout()
        row1.addWidget(self.lbl_name)
        row1.addWidget(self.change_name)
        row1.addStretch()
        row2 = QHBoxLayout()
        row2.addWidget(self.lbl_type)
        row2.addWidget(self.change_type)
        row2.addStretch()

        layout.addLayout(row2)
        layout.addLayout(row1)
        self.type_frame.setLayout(layout)

    def make_frame4(self):
        row2 = QHBoxLayout()
        row2.addWidget(self.radio_manual)
        row2.addWidget(self.input_manual)
        row2.addStretch()
        col1 = QVBoxLayout()
        col1.addLayout(row2)
        col1.addWidget(self.radio_max)
        col1.addWidget(self.radio_min)
        col1.addWidget(self.tableB)
        col1.addStretch()

        layout = QHBoxLayout()
        layout.addLayout(col1)
        layout.addStretch()
        self.frame3.setLayout(layout)


def make_table(column_labels, column_size, rows, parameters=None):
    table = QTableWidget()
    table.setRowCount(rows)
    table.setColumnCount(len(column_size))
    for x, col in enumerate(column_size):
        table.setColumnWidth(x, col)
    table.setHorizontalHeaderLabels(column_labels)
    table.verticalHeader().setMinimumSectionSize(18)
    table.verticalHeader().setMaximumSectionSize(18)
    table.verticalHeader().setDefaultSectionSize(18)
    table.verticalHeader().setMinimumWidth(18)
    table.verticalHeader().setMaximumWidth(18)

    table.horizontalHeader().setDefaultAlignment(Qt.AlignTop | Qt.AlignHCenter)
    table.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
    table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
    table.setFixedWidth(sum(column_size))
    table.setFixedHeight(table.rowCount() * 18 + 25)
    table.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)
    table.verticalHeader().setVisible(False)

    if parameters is not None:
        for x, parameter in enumerate(parameters):
            name = QTableWidgetItem(parameter[0])
            unit = QTableWidgetItem(parameter[1])
            unit.setTextAlignment(Qt.AlignRight)

            table.setItem(x, 0, name)
            table.setItem(x, 1, unit)

    return table

class Button(QPushButton):
    def __init__(self, title=None, width=50, height=22):
        self.title = title
        self.width = width
        self.height = height
        super().__init__()
        self.setText(self.title)
        self.setFixedSize(self.width, self.height)

class Combo(QComboBox):
    def __init__(self, width=200, height=22):
        self.width = width
        self.height = height
        super().__init__()
        self.setFixedSize(self.width, self.height)

class Radio(QRadioButton):
    def __init__(self, title=None, width=300, height=22):
        self.title = title
        self.width = width
        self.height = height
        super().__init__()
        self.setText(title)
        self.setFixedSize(self.width, self.height)

class LineEdit(QLineEdit):
    def __init__(self, width=65, height=22, regex=None):
        self.width = width
        self.height = height
        super().__init__()
        self.setFixedSize(self.width, self.height)

class Label(QLabel):
    def __init__(self, title=None, alignment=(Qt.AlignLeft | Qt.AlignVCenter), width=200, height=22, tooltip=None):
        self.title = title
        self.width = width
        self.height = height
        self.alignment = alignment
        self.tip = tooltip
        super().__init__()
        self.setFixedSize(self.width, self.height)
        self.setAlignment(self.alignment)
        self.setText(self.title)
        self.setToolTip(self.tip)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Layout()
    ex.show()
    sys.exit(app.exec_())
Reply
#2
Have you tried QStackedWidget or QStackedLyout? Instead of repopulating one frame you create different views that are all mapped to the same place in the window. It is kind of like using a QTabWidget without the tabs. As for clearing the fields of old values, that is much easier than tearing down and rebuilding a layout.
Reply
#3
(May-13-2020, 09:04 PM)deanhystad Wrote: Have you tried QStackedWidget or QStackedLyout? Instead of repopulating one frame you create different views that are all mapped to the same place in the window. It is kind of like using a QTabWidget without the tabs. As for clearing the fields of old values, that is much easier than tearing down and rebuilding a layout.

Thanks for your suggestion. No, I have not, but it is certainly worth looking at it. How would you suggest clearing the old values then?
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  event driven coding PyQt6 on Combobox change merrittr 3 1,917 May-03-2023, 03:35 AM
Last Post: merrittr
  [PyQt] QWidgetAction of QFrame not showing in menu malonn 4 1,943 Sep-22-2022, 10:49 PM
Last Post: malonn
  [PyQt] How can I sync Combobox index to other combobox index? nickzsche 2 2,335 Jan-03-2022, 12:29 PM
Last Post: Axel_Erfurt

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020