Search code examples
pythonkivyglobal-variables

Using global variables with Kivy Screen Manager


I'm a beginner trying to make an application where I can first select items out of a predetermined list and then, on the next screen, see a list of only those selected items.

I made a grid with 2 colums : checkboxes and labels. I made lists out of these colums and zipped those together to receive a "result" list of items where the corresponding checkbox indices have "down" as a state.

However I can't seem to get this updated result list out of the ShopInput class into the SecondWindow class.

I've tried many things that I've found on here but I seem to be completely stuck. Could anyone please guide me on how to proceed to make the result list update on the second screen?

My code:

shoppinglist.py :

import kivy
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.image import Image
from kivy.uix.checkbox import CheckBox
from kivy.uix.scrollview import ScrollView
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.gridlayout import GridLayout
from kivy.lang import Builder

result = ["test", "test2", "test3"]

item_dictionary = {
    "item1": "Cookies",
    "item2": "Milk",
    "item3": "Honey"
}


class ShopInput(Screen):
    obj_listitem1 = ObjectProperty(None)
    obj_listitem2 = ObjectProperty(None)
    obj_listitem3 = ObjectProperty(None)

    def button_press(self):
        products = list(item_dictionary.values())

        added_item_list = []
        added_item_list.append(self.obj_listitem1.state)
        added_item_list.append(self.obj_listitem2.state)
        added_item_list.append(self.obj_listitem3.state)

        global result
        result.clear()
        result.append([x for x, y in zip(products, added_item_list) if y == 'down'])

        print(result)  # Temporarily to see what gets added to the result list
        added_item_list.clear()


class SecondWindow(Screen):

    def __init__(self, **kwargs):
        super(SecondWindow, self).__init__(**kwargs)
        global result
        self.add_widget(Label(text=(f'{result}')))


class WindowManager(ScreenManager):
    pass


kv = Builder.load_file("shoppinglist.kv")


class ShoppingListApp(App):
    def build(self):
        return kv


if __name__ == "__main__":
    ShoppingListApp().run()



shoppinglist.kv :

WindowManager:
    ShopInput:
    SecondWindow:

<ShopInput>:
    name: "first"

    obj_listitem1: listitem1
    obj_listitem2: listitem2
    obj_listitem3: listitem3

    GridLayout:
        cols: 1
        rows: 3
        size: root.width, root.height
        padding: 2

        Label:
            text:"Make Your Shopping List"
            size_hint_y:0.2

        ScrollView:
            do_scroll_x: False
            do_scroll_y: True
            size_hint_y:0.675

            GridLayout:
                cols: 2
                size_hint_y: 1.5
                height: self.minimum_height

                Label:
                    text: "Add to list:"

                Label:
                    text: "Product:"

                CheckBox:
                    id: listitem1

                Label:
                    text: "Cookies"

                CheckBox:
                    id: listitem2

                Label:
                    text: "Milk"

                CheckBox:
                    id: listitem3

                Label:
                    text: "Honey"

        GridLayout:
            cols: 2
            size_hint_y:0.075

            Button:
                text:"Add"
                on_press: root.button_press()

            Button:
                text:"Next"
                on_release: root.manager.current = "second"

<SecondWindow>:
    name: "second"


Thanks!


Solution

  • You are trying to set the Label text of SecondWindow in its __init__() method, which is called during the Builder.load_file(), long before the user has chosen anything. Try changing the SecondWindow class to:

    class SecondWindow(Screen):
    
        def __init__(self, **kwargs):
            super(SecondWindow, self).__init__(**kwargs)
            print('init')
    
        def on_enter(self, *args):
            global result
            self.add_widget(Label(text=(f'{result}')))
    

    This delays the setting the Label text until the SecondWindow is displayed by using the on_enter() method of Screen.