Search code examples
pythonpyqtpyqt5qscrollarea

PyQt5 set widget size to minimum and fix


def __init__(self):
    super().__init__()
    self.order_list = [str(i) * 2 * i for i in range(20)]
    self.space = 18
    self.init_ui()

def init_ui(self):
    self.setGeometry(300, 300, 300, 300)

    self.layout = Qw.QGridLayout(self)

    self.menu = Qw.QWidget()
    self.menu.setFixedHeight(self.space * len(self.order_list) + 5)
    self.menu.items = []
    for n, i in enumerate(self.order_list):
        btn = Qw.QCheckBox(i, self.menu)
        btn.move(5, self.space * n + 5)
        btn.setFixedHeight(15)
        self.menu.items.append(btn)
    self.menu_scroll = Qw.QScrollArea()
    self.menu_scroll.setWidgetResizable(True)
    self.menu_scroll.setWidget(self.menu)
    self.layout.addWidget(self.menu_scroll, 0, 0, 1, 1)
    self.layout.setColumnStretch(0, 10)

    self.rec = Qw.QWidget()
    self.rec_box = Qw.QVBoxLayout(self.rec)
    self.rec.setLayout(self.rec_box)
    self.rec_scroll = Qw.QScrollArea()
    self.rec_scroll.setWidget(self.rec)

    self.layout.addWidget(self.rec_scroll, 0, 1, 1, 1)
    self.layout.setColumnStretch(1, 9)

    self.order_btn = Qw.QPushButton('Order')
    self.order_btn.setFixedSize(80, 30)
    self.order_btn.clicked.connect(self.get_ordered)
    self.layout.addWidget(self.order_btn, 1, 0, 1, 2, alignment=Qc.Qt.AlignCenter)

So i have this code. It consists of grid layout with two QScrollAreas and one button. I need to set self.menu's size to fixed so it can be scrolled throught all the time it's not big enough. Already done so with vertical, but how i can get menu resized to it's biggest widget size? Setting WidgetResizeable to False just makes ScrollArea empty. (Don't look at right area, I will change it when left one will be taken care off)

I should also mention, that need some widgets to be added on click of order_btn. Thats how code with Layouts works, but it breaks spacings and placement.

def __init__(self):
    super().__init__()
    self.order_list = [str(i) * 2 * i for i in range(20)]
    self.space = 10
    self.init_ui()

def init_ui(self):
    self.setGeometry(300, 300, 300, 300)

    self.layout = Qw.QGridLayout(self)

    self.menu = Qw.QWidget()
    lay = Qw.QVBoxLayout(self.menu)
    self.menu.items = []
    for n, i in enumerate(self.order_list):
        btn = Qw.QCheckBox(i)
        btn.setFixedHeight(15)
        lay.addWidget(btn)
        self.menu.items.append(btn)

    self.menu_scroll = Qw.QScrollArea(widgetResizable=True)
    self.menu_scroll.setWidget(self.menu)
    self.layout.addWidget(self.menu_scroll, 0, 0, 1, 1)
    self.layout.setColumnStretch(0, 10)

    self.rec = Qw.QWidget()
    self.rec.items = []
    self.lay2 = Qw.QVBoxLayout(self.rec)
    for n, i in enumerate(self.order_list):
        btn = Qw.QCheckBox(i)
        btn.setFixedHeight(15)
        self.lay2.addWidget(btn)
        self.rec.items.append(btn)

    self.rec_scroll = Qw.QScrollArea(widgetResizable=True)
    self.rec_scroll.setWidget(self.rec)
    self.layout.addWidget(self.rec_scroll, 0, 0, 1, 1)
    self.layout.setColumnStretch(0, 10)

    self.layout.addWidget(self.rec_scroll, 0, 1, 1, 1)
    self.layout.setColumnStretch(1, 9)

    self.order_btn = Qw.QPushButton('Order')
    self.order_btn.setFixedSize(80, 30)
    self.order_btn.clicked.connect(self.get_ordered)
    self.layout.addWidget(self.order_btn, 1, 0, 1, 2, alignment=Qc.Qt.AlignCenter)

@Qc.pyqtSlot()
def get_ordered(self):
    try:
        while self.rec.items:
            self.rec.items.pop(-1).deleteLater()
        n = 0
        for i in self.menu.items:
            if i.checkState():
                item = Qw.QLabel()
                item.setFixedHeight(15)
                item.setText(i.text())
                item.show()
                self.rec.items.append(item)
                self.lay2.addWidget(item)
                n += 1
    except Exception as error:
        print(error)

Solution

  • You do not have to calculate anything, and if you add an item, are you going to recalculate? What you should do is use a QVBoxLayout to calculate the right size:

    from PyQt5 import QtCore as Qc
    from PyQt5 import QtWidgets as Qw
    
    class Widget(Qw.QWidget):
        def __init__(self):
            super().__init__()
            self.order_list = [str(i) * 2 * i for i in range(20)]
            self.init_ui()
    
        def init_ui(self):
            self.setGeometry(300, 300, 300, 300)
    
            layout = Qw.QGridLayout(self)
    
            self.menu = Qw.QWidget()
            lay = Qw.QVBoxLayout(self.menu)
            self.menu.items = []
            for n, i in enumerate(self.order_list):
                btn = Qw.QCheckBox(i)
                btn.setFixedHeight(15)
                lay.addWidget(btn)
                self.menu.items.append(btn)
            lay.addStretch()
    
            self.menu_scroll = Qw.QScrollArea(widgetResizable=True)
            self.menu_scroll.setWidget(self.menu)
            layout.addWidget(self.menu_scroll, 0, 0, 1, 1)
            layout.setColumnStretch(0, 10)
    
            self.rec = Qw.QWidget()
            self.rec_box = Qw.QVBoxLayout(self.rec)
            self.rec_scroll = Qw.QScrollArea()
            self.rec_scroll.setWidget(self.rec)
    
            layout.addWidget(self.rec_scroll, 0, 1, 1, 1)
            layout.setColumnStretch(1, 9)
    
            self.order_btn = Qw.QPushButton('Order')
            self.order_btn.setFixedSize(80, 30)
            self.order_btn.clicked.connect(self.get_ordered)
            layout.addWidget(self.order_btn, 1, 0, 1, 2, alignment=Qc.Qt.AlignCenter)
    
        @Qc.pyqtSlot()
        def get_ordered(self):
            pass
    
    if __name__ == '__main__':
        import sys
        app = Qw.QApplication(sys.argv)
        w = Widget()
        w.show()
        sys.exit(app.exec_())
    

    Removing elements from a layout is always a bad idea, it is best to hide or show when necessary.

    from PyQt5 import QtCore as Qc
    from PyQt5 import QtWidgets as Qw
    
    class Widget(Qw.QWidget):
        def __init__(self):
            super().__init__()
            self.order_list = [str(i) * 2 * i for i in range(20)]
            self.init_ui()
    
        def init_ui(self):
            self.setGeometry(300, 300, 300, 300)
            self.layout = Qw.QGridLayout(self)
    
            self.menu = Qw.QWidget()
            lay = Qw.QVBoxLayout(self.menu)
            self.menu.items = []
            for n, i in enumerate(self.order_list):
                btn = Qw.QCheckBox(i)
                btn.setFixedHeight(15)
                lay.addWidget(btn)
                self.menu.items.append(btn)
            lay.addStretch()
    
            self.menu_scroll = Qw.QScrollArea(widgetResizable=True)
            self.menu_scroll.setWidget(self.menu)
            self.layout.addWidget(self.menu_scroll, 0, 0, 1, 1)
            self.layout.setColumnStretch(0, 10)
    
            self.rec = Qw.QWidget()
            self.rec.items = []
            lay2 = Qw.QVBoxLayout(self.rec)
            for n, i in enumerate(self.order_list):
                btn = Qw.QLabel(i)
                btn.setFixedHeight(15)
                lay2.addWidget(btn)
                self.rec.items.append(btn)
            lay2.addStretch()
    
            self.rec_scroll = Qw.QScrollArea(widgetResizable=True)
            self.rec_scroll.setWidget(self.rec)
            self.layout.addWidget(self.rec_scroll, 0, 0, 1, 1)
            self.layout.setColumnStretch(0, 10)
    
            self.layout.addWidget(self.rec_scroll, 0, 1, 1, 1)
            self.layout.setColumnStretch(1, 9)
    
            self.order_btn = Qw.QPushButton('Order')
            self.order_btn.setFixedSize(80, 30)
            self.order_btn.clicked.connect(self.get_ordered)
            self.layout.addWidget(self.order_btn, 1, 0, 1, 2, alignment=Qc.Qt.AlignCenter)
    
        @Qc.pyqtSlot()
        def get_ordered(self):
            for checkbox, label in zip(self.menu.items, self.rec.items):
                label.setVisible(checkbox.isChecked())
    
    if __name__ == '__main__':
        import sys
        app = Qw.QApplication(sys.argv)
        w = Widget()
        w.show()
        sys.exit(app.exec_())