Search code examples
pythonpython-3.xpyqtpyqt5qwidget

Rezising QWidget afer expanding/collapsing it


I am trying to automatically resize the QWidget dependent on whether it is expanded/collapsed. I have tried few ways posted here and here.

I did not manage to adopt these so that it worked the way I want: I would like the QWidget to resize itself when it is expanded (it works now) but after collapsing it (unchecking the QCheckBox) its size remains too big and does not change back to its original state.

Here is my code:

from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys

class CheckableComboBox(QComboBox):
    def __init__(self, parent = None):
        super(CheckableComboBox, self).__init__(parent)
        self.view().pressed.connect(self.handleItemPressed)
        self.setModel(QStandardItemModel(self))

        self.setStyleSheet("QComboBox{"
                           "font-size:11px;"
                           "color:black;"
                           "background-color:white;"
                           "border:1px solid black;"
                           "padding:1px;""}")

        self.setEditable(True)
        self.lineEdit().setAlignment(Qt.AlignCenter)
        self.lineEdit().setReadOnly(True)
        self.setMinimumSize(150, 40)

    def handleItemPressed(self, index):
        item = self.model().itemFromIndex(index)
        if item.text() != ' ' and item.checkState() == Qt.Checked:
            item.setCheckState(Qt.Unchecked)
        if item.text() != ' ' and item.checkState() != Qt.Checked:
            item.setCheckState(Qt.Checked)

class Example(QWidget):

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

##        self.setFixedSize(350, 280)
        self.init_UI()

    def init_UI(self):
        self.years = [' ', '2017', '2018', '2019', '2020']
        self.months = [' ', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
        self.metrics = [' ', 'Seller', 'Section', 'Store']
        self.units = [' ', 'Number of Pieces Sold', 'Total Value']

        self.setWindowTitle('Dialog')

        self.sMetric = QLabel('Select metric(s):')
        self.sUnit = QLabel('Select unit(s):')
        self.okButton = QPushButton('Ok')
        self.cancelButton = QPushButton('Cancel')

        self.okButton.clicked.connect(self.okClicked)
        self.cancelButton.clicked.connect(self.cancelClicked)

        for i in (self.sMetric, self.sUnit, self.okButton, self.cancelButton):
            i.setFixedHeight(40)
            i.setFixedWidth(150)

        self.timeWise = QCheckBox('Time-wise View')
        self.timeWise.stateChanged.connect(self.on_checked)

        self.metricCombo = CheckableComboBox()
        for index, element in enumerate(self.metrics):
            self.metricCombo.addItem(element)
            if index > 0:
                item = self.metricCombo.model().item(index, 0)
                item.setCheckState(Qt.Unchecked)

        self.unitCombo = CheckableComboBox()
        for index, element in enumerate(self.units):
            self.unitCombo.addItem(element)
            if index > 0:
                item = self.unitCombo.model().item(index, 0)
                item.setCheckState(Qt.Unchecked)

        self.grid = QGridLayout()
        self.grid.setSpacing(10)

        self.grid.addWidget(self.sMetric, 1, 0)
        self.grid.addWidget(self.metricCombo, 1, 1)
        self.grid.addWidget(self.sUnit, 2, 0)
        self.grid.addWidget(self.unitCombo, 2, 1)
        self.grid.addWidget(self.timeWise, 3, 0)
        self.grid.addWidget(self.okButton, 6, 0)
        self.grid.addWidget(self.cancelButton, 6, 1)

        self.setLayout(self.grid)

    def on_checked(self, state):
        if state == Qt.Checked:
            print('Checked')

            self.sYear = QLabel('Select year(s):')
            self.sMonth = QLabel('Select month(s):')

            for i in (self.sYear, self.sMonth):
                i.setFixedHeight(40)
                i.setFixedWidth(150)

            self.monthCombo = CheckableComboBox()
            for index, element in enumerate(self.months):
                self.monthCombo.addItem(element)
                if index > 0:
                    item = self.monthCombo.model().item(index, 0)
                    item.setCheckState(Qt.Unchecked)

            self.yearCombo = CheckableComboBox()
            for index, element in enumerate(self.years):
                self.yearCombo.addItem(element)
                if index > 0:
                    item = self.yearCombo.model().item(index, 0)
                    item.setCheckState(Qt.Unchecked)

            self.grid.addWidget(self.sYear, 4, 0)
            self.grid.addWidget(self.yearCombo, 4, 1)
            self.grid.addWidget(self.sMonth, 5, 0)
            self.grid.addWidget(self.monthCombo, 5, 1)

        else:
            print('Unchecked')

            self.sYear.deleteLater()
            self.sMonth.deleteLater()
            self.monthCombo.deleteLater()
            self.yearCombo.deleteLater()

    def okClicked(self):
        self.close()

    def cancelClicked(self):
        self.close()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    main = Example()
    main.show()
    sys.exit(app.exec_())

Any suggestions how to proceed?


Solution

  • You must set the size restriction of the design that contains all the widgets in QLayout::SetFixedSize:

    QLayout::SetFixedSize 3 The main widget's size is set to sizeHint(); it cannot be resized at all.

    In addition to this an improvement to your code would not create and then remove widgets, but better to hide them or make it visible as desired.

    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
    import sys
    
    class CheckableComboBox(QComboBox):
        def __init__(self, parent = None):
            super(CheckableComboBox, self).__init__(parent)
            self.view().pressed.connect(self.handleItemPressed)
            self.setModel(QStandardItemModel(self))
    
            self.setStyleSheet("QComboBox{"
                               "font-size:11px;"
                               "color:black;"
                               "background-color:white;"
                               "border:1px solid black;"
                               "padding:1px;""}")
    
            self.setEditable(True)
            self.lineEdit().setAlignment(Qt.AlignCenter)
            self.lineEdit().setReadOnly(True)
            self.setMinimumSize(150, 40)
    
        def handleItemPressed(self, index):
            item = self.model().itemFromIndex(index)
            if item.text() != ' ' and item.checkState() == Qt.Checked:
                item.setCheckState(Qt.Unchecked)
            if item.text() != ' ' and item.checkState() != Qt.Checked:
                item.setCheckState(Qt.Checked)
    
    class Example(QWidget):
    
        def __init__(self):
            super().__init__()
    
    ##        self.setFixedSize(350, 280)
            self.init_UI()
    
        def init_UI(self):
            self.years = [' ', '2017', '2018', '2019', '2020']
            self.months = [' ', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
            self.metrics = [' ', 'Seller', 'Section', 'Store']
            self.units = [' ', 'Number of Pieces Sold', 'Total Value']
    
            self.setWindowTitle('Dialog')
    
            self.sMetric = QLabel('Select metric(s):')
            self.sUnit = QLabel('Select unit(s):')
            self.okButton = QPushButton('Ok')
            self.cancelButton = QPushButton('Cancel')
    
            self.okButton.clicked.connect(self.okClicked)
            self.cancelButton.clicked.connect(self.cancelClicked)
    
            for i in (self.sMetric, self.sUnit, self.okButton, self.cancelButton):
                i.setFixedHeight(40)
                i.setFixedWidth(150)
    
            self.timeWise = QCheckBox('Time-wise View')
            self.timeWise.toggled.connect(self.on_checked)
    
            self.metricCombo = CheckableComboBox()
            for index, element in enumerate(self.metrics):
                self.metricCombo.addItem(element)
                if index > 0:
                    item = self.metricCombo.model().item(index, 0)
                    item.setCheckState(Qt.Unchecked)
    
            self.unitCombo = CheckableComboBox()
            for index, element in enumerate(self.units):
                self.unitCombo.addItem(element)
                if index > 0:
                    item = self.unitCombo.model().item(index, 0)
                    item.setCheckState(Qt.Unchecked)
    
            self.grid = QGridLayout()
            self.grid.setSpacing(10)
    
            self.grid.addWidget(self.sMetric, 1, 0)
            self.grid.addWidget(self.metricCombo, 1, 1)
            self.grid.addWidget(self.sUnit, 2, 0)
            self.grid.addWidget(self.unitCombo, 2, 1)
            self.grid.addWidget(self.timeWise, 3, 0)
            self.grid.addWidget(self.okButton, 6, 0)
            self.grid.addWidget(self.cancelButton, 6, 1)
    
            self.setLayout(self.grid)
    
    
            self.sYear = QLabel('Select year(s):')
            self.sMonth = QLabel('Select month(s):')
    
            for i in (self.sYear, self.sMonth):
                i.setFixedHeight(40)
                i.setFixedWidth(150)
    
            self.monthCombo = CheckableComboBox()
            for index, element in enumerate(self.months):
                self.monthCombo.addItem(element)
                if index > 0:
                    item = self.monthCombo.model().item(index, 0)
                    item.setCheckState(Qt.Unchecked)
    
            self.yearCombo = CheckableComboBox()
            for index, element in enumerate(self.years):
                self.yearCombo.addItem(element)
                if index > 0:
                    item = self.yearCombo.model().item(index, 0)
                    item.setCheckState(Qt.Unchecked)
    
            self.grid.addWidget(self.sYear, 4, 0)
            self.grid.addWidget(self.yearCombo, 4, 1)
            self.grid.addWidget(self.sMonth, 5, 0)
            self.grid.addWidget(self.monthCombo, 5, 1)
            self.grid.setSizeConstraint(QLayout.SetFixedSize)
    
            self.on_checked(False)
    
        def on_checked(self, checked):
            self.sYear.setVisible(checked)
            self.sMonth.setVisible(checked)
            self.monthCombo.setVisible(checked)
            self.yearCombo.setVisible(checked)
    
        def okClicked(self):
            self.close()
    
        def cancelClicked(self):
            self.close()
    
    if __name__ == '__main__':
    
        app = QApplication(sys.argv)
        main = Example()
        main.show()
        sys.exit(app.exec_())