QGroupBox buttons not showing

440 Views Asked by At

So basically I'm trying to make an updating QGroupBox with some QPushButtons inside of it, here's the "updating" method and it is always called right after the list is changed:

    def repaintList(self):    

        btn_ls = []

        for i in range(len(self.list)):
            btn_ls.append(buttons.QPushButton("t"))


        layout = QVBoxLayout()

        for i in range(len(btn_ls)):
            layout.addWidget(btn_ls[i])


it's pretty simple, I have a method that updates the list for me and I've tested the functionality with print(len(self.list)) and print(btn_ls) enough to know that the list updating works, and that the btn_ls is made properly, but I'm not sure why it's not updating on the actual screen.

I've made an example of a simplified version of what I'm trying to accomplish:

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


class TestWindow(QWidget):

    def __init__(self):

        super(TestWindow,self).__init__()

        self.list = []

        self.cont = TestContainer(self.list, "Test Box",  self)

        self.adder = AdderButton("Add one", self, self.list, self.cont)


        layout = QVBoxLayout()

        layout.addWidget(self.cont)


        self.setLayout(layout)
        self.setGeometry(200,200,200,200)



class TestContainer(QGroupBox):


    def __init__(self,ls,ttl,pare):

        super(TestContainer,self).__init__(ttl,pare)

        self.list = ls


        self.repaintButtons()




    def repaintButtons(self):

        btn_ls = []

        for i in range(len(self.list)):
            btn_ls.append(QPushButton(str(i),self))


        print(self.list)
        layout = QVBoxLayout()
        

        for i in range(len(btn_ls)):

            layout.addWidget(btn_ls[i])


        
        self.setLayout(layout)



class AdderButton(QPushButton):


    def __init__(self,txt,pare,ls,displ):
        super(AdderButton,self).__init__(txt,pare)

        self.disp = displ
        self.list = ls

        self.clicked.connect(self.addOne)


    def addOne(self):
        self.list.append(1)
        self.disp.repaintButtons()





    
def main():


    app = QApplication(sys.argv)

    tw = TestWindow()


    tw.show()

    app.exec()



if __name__ == "__main__":
    main()

The desired result is that every time I press the button a new QPushButton would appear on the screen...

2

There are 2 best solutions below

2
furas On

I has to use self.layout() instead of layout to see widgets.

def repaintButtons(self):

    btn_ls = []

    for i in range(len(self.list)):
        btn_ls.append(QPushButton(str(i),self))


    print(self.list)

    layout = QVBoxLayout()
    self.setLayout(layout)  # it has to be before `self.layout()`

    for i in range(len(btn_ls)):

        self.layout().addWidget(btn_ls[i])

BTW: self.setLayout() has to be before self.layout()


But there is other problem.

Using again

 layout = QVBoxLayout() 
 self.setLayout(layout)

doesn't remove previous layout and it doesn't remove previous buttons and finally it adds again the same buttons to layout.

You would need add only new buttons to layout instead of adding all buttons again.

Or you would have to remove widgets from layout before adding them again.


EDIT:

Code which adds new button without removing previous buttons

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


class TestWindow(QWidget):

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

        self.list = []

        self.container = TestContainer("Test Box", self, self.list)

        self.adder = AdderButton("Add one", self, self.container)

        layout = QVBoxLayout()

        layout.addWidget(self.container)

        self.setLayout(layout)
        self.setGeometry(200,200,200,200)


class TestContainer(QGroupBox):

    def __init__(self, title, parent, lst):
        super(TestContainer,self).__init__(title, parent)

        self.list = lst

        layout = QVBoxLayout()
        self.setLayout(layout)

        # create buttons at start using `self.list`
        for item in self.list:
            self.layout().addWidget(QPushButton(str(item), self))

    def addButton(self, item):
        # add new item to `self.list` and create new button
        self.list.append(item)
        self.layout().addWidget(QPushButton(str(item), self))


class AdderButton(QPushButton):

    def __init__(self, text, parent, target):
        super(AdderButton,self).__init__(text, parent)

        self.target = target

        self.clicked.connect(self.addOne)

    def addOne(self):
        self.target.addButton(1)

    
def main():
    app = QApplication(sys.argv)
    tw = TestWindow()
    tw.show()
    app.exec()


if __name__ == "__main__":
    main()

There are examples how to remove items but they don't work for me

0
Henrique Lee On

After doing more research, I came across the update() function which basically repaints the QGroupBox. It works in the sense that it adds one button at a time and updates each time a button is added.

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


class TestWindow(QWidget):

    def __init__(self):

        super(TestWindow,self).__init__()

        self.list = []

        self.cont = TestContainer(self.list, "Test Box",  self)

        self.adder = AdderButton("Add one", self, self.list, self.cont)


        layout = QVBoxLayout()

        layout.addWidget(self.cont)


        self.setLayout(layout)
        self.setGeometry(200,200,200,200)



class TestContainer(QGroupBox):


    def __init__(self,ls,ttl,pare):

        super(TestContainer,self).__init__(ttl,pare)

        self.list = ls
        self.layout = QVBoxLayout()


        self.setLayout(self.layout)


    def addButton(self):
        
        self.layout.addWidget(QPushButton("thing"))
        



class AdderButton(QPushButton):


    def __init__(self,txt,pare,ls,displ):
        super(AdderButton,self).__init__(txt,pare)

        self.disp = displ
        self.list = ls

        self.clicked.connect(self.addOne)


    def addOne(self):
        self.list.append(1)
        self.disp.addButton()
        self.disp.update()





    
def main():


    app = QApplication(sys.argv)

    tw = TestWindow()


    tw.show()

    app.exec()



if __name__ == "__main__":
    main()