-1

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...

Henrique Lee
  • 59
  • 1
  • 1
  • 7
  • 1
    please provide a [mre] – eyllanesc Jun 26 '20 at 10:54
  • I've provided a simplified example above where the number of buttons is based on the number of ones in the TestWindow's self.list! – Henrique Lee Jun 26 '20 at 15:54
  • 1
    BTW: in `repaintList` you could use one `for`-loop without `btn_ls = []`. – furas Jun 26 '20 at 16:48
  • 1
    did you run it in console/terminal to see error message ? If you get error then you should add it in question. When I run I see some error - it says you can't add new `layout`. Maybe `QGroupBox` has different method to add elements. Or you have to remove old widgets in layout and add new widgets to existing layout without createing new layout. – furas Jun 26 '20 at 16:53
  • That's really weird because when I run it, there are no errors?? Everything works except the buttons don't appear in the QGroupBox. – Henrique Lee Jun 26 '20 at 17:35
  • I get error when I press button - and I see it in console/terminal but program still runs. – furas Jun 26 '20 at 17:41
  • that's very strange as it works when I try it...maybe a different version? Anyways thank you so much for trying to help! – Henrique Lee Jun 26 '20 at 17:46
  • I can see buttons only if I use `setLayout()` only once (ie. in `__init__`) and later in`repaintButtons` I add button(s) using `addWidget` without using `setLayout()` again. – furas Jun 26 '20 at 17:54

2 Answers2

1

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()

Henrique Lee
  • 59
  • 1
  • 1
  • 7
0

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

furas
  • 134,197
  • 12
  • 106
  • 148
  • I know now that this probably wasn't the best idea... though the solution you gave solved the problem perfectly so thank you very much for it! – Henrique Lee Jun 26 '20 at 19:14
  • I added minimal working code which add button without removing layout - but it can't remove buttons if you will need. I also added links to other questions which described how to remove widgets and layout but I couldn't create working example. – furas Jun 26 '20 at 19:21