Search code examples
pythonkivypeewee

Updating the amount of widgets on a screen when you open it?


I have a Screen that holds a ScrollView that holds a StackLayout of buttons. I can generate as many buttons as I have rows in my database table, but only when the app is first loaded. I have a button that can add rows to my table, but no more buttons are added to the screen unless the app is fully closed and reopened.

<InventoryScreen>:
    on_pre_enter: root.updateInv(self)
    name: "inventory" 
    BoxLayout:
        orientation: "vertical"
        Label:
            text: "Inventory"
            size_hint: 1, .25
        ScrollInventory:
        Button:
            text: "Back"
            size_hint: 1, None
            on_release:
                app.root.current = "Options"
                root.manager.transition.direction = "right"

<ScrollInventory@ScrollView>:
    InventoryStack: 
        size_hint: 1, None
        height: self.minimum_height     

<InventoryStack>:
    orientation: "lr-tb"
    padding: ("20dp", "20dp")
    spacing: "20dp", "20dp"
class InventoryStack(StackLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        for i in Inventory.select():
            size = dp(100)
            dictItem = model_to_dict(i) 
            print(dictItem['name'])
            invButton = Button(text=dictItem['name'], size_hint=(None, None), size=(size, size))
------------self.add_widget(invButton)
        print("-" * 35)

    def viewInventory(self):
        for i in Inventory.select():
            size = dp(100)
            dictItem = model_to_dict(i) 
            print(dictItem['name'])
            invButton = Button(text=dictItem['name'], size_hint=(None, None), size=(size, size))
------------self.add_widget(invButton)
        print("-" * 35)
        
class InventoryScreen(Screen):
    def updateInv(self, *largs):
        InventoryStack().viewInventory()  

I've minimized this code as much as possible to identify the problem. It works exactly how I want it to EXCEPT for the self.add_widget(invButton) lines. Just not sure where to look in the kivy docs to find a solution. Thanks in advance.


Solution

  • Your line of code:

    InventoryStack().viewInventory() 
    

    is creating a new instance of InventoryStack, and calling viewInventory() on that new instance. That new instance is not the instance that appears in your GUI, so it has no visible effect. You need a reference to the InventoryStack that is actually in your GUI.

    One way to solve this is to create a class variable that contains a reference to the correct instance. Something like this:

    class InventoryStack(StackLayout):
        instance = None  # class variable to hole reference to the instance
    
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            InventoryStack.instance = self
            .
            .
            .
    

    Then use that reference in the updateInv() method:

    class InventoryScreen(Screen):
        def updateInv(self, *largs):
            InventoryStack.instance.viewInventory()
    

    This is the beginnings of a Singleton. See this question.