Search code examples
pythonkivy-language

Im New on kivy Python classes


Im new on kivy I trying to do file.kv including

AddLocationForm:
<AddLocationForm@BoxLayout>:
    orientation:'vertical'
    Button:
        on_press:
            Test()
<Test@BoxLayout>:
    Label:
        text:"button was clicked"

I want that when i click on button The function on other class execute


Solution

  • In Kivy, when you define a widget like this:

    <SomeWidget>:
    

    You are defining a root widget rule, this widget can only affect children widget inside it.

    For example:

    <SomeWidget>:
        BoxLayout:
            Button:
                text: 'Test Two'
            Button:
                text: 'Test One'
    

    To affect a property within a Root Widget, you need to use ids. There are two ways to do this, you can do root.ids[X].property

    Where X is the position of the Widget, you can also use self-created ids (my prefer method since it is more clear what I'm affecting)

    <SomeWidget>:
         BoxLayout:
             Button:
                 id: ButtonOne
                 text: 'Button One'
                 on_press: print(self.text)
             Button:
                 text:
                 on_press: root.ids.ButtonOne.text = 'Button Two Was Clicked'
    

    In here, root refers to the top-level widget or 'root' widget which is encased in

    <WIDGETNAMEHRE>: 
    

    Then ids is essentially a dictionary that stores all ids (including the ids of children so you only need to go root.ids.button and not root.ids.buttonparent.ids.button, typically speaking)

    You have two root widgets defined in your example. The best way to think of these are treat them as classes (since that is essentially what they are). When you have a python class, you don't use the class directly, you create a an Object from the class.

    So what you need to do is add an Object of the other Widget Class to your parent Widget.

    e.g

    <TestWidget>:
        Button:
            text: 'change text'
            on_press: root.parent.parent.ids.ButtonOne.text = 'Button Was Clicked'
    
    <PrimaryWidget>:
        BoxLayout:
            TestWidget:
            Button:
                id: ButtonOne
                text: 'Click the other one'
    

    In this case, when we click the Button, we're first going to root (ie TestWidget), then we're getting TestWidget's parent (in this case the BoxLayout under Primary), then we're getting the Parent of that (PrimaryWidget), then we're accessing the ids of PrimaryWidget to which ButtonOne is of.

    You can also access things through the app instance as well and work downwards from your main widget.

    <TestWidget>:
        Button:
            text: 'change text'
            on_press: app.root.ids.ButtonOne.text = 'Button Was Clicked'
    

    In this case, we go to app, then app's root widget (the PrimaryWidget, basically the kv file that gets returned in the def build(self) method, then we access ids of ButtonOne.

    One last bit on ids too is that you can access the ids of custom child widgets as well, for example:

    <TestWidget>:
        Button:
            id: ButtonTwo
            text: 'change text'
            on_press: app.root.ids.ButtonOne.text = 'Button Was Clicked'
    
    <PrimaryWidget>:
        BoxLayout:
            TestWidget:
                id: test
            Button:
                id: ButtonOne
                text: 'Click this one'
                on_press: root.ids.test.ids.ButtonTwo.text = 'The other button was clicked'
    

    So in this case, we're going to root (primarywidget) then we're accessing the TestWidget id'ed as 'test' then we're accessing its ButtonTwo from its ids.

    The reason TestWidget requires its own id here, is because if we use more than one TestWidget, we need to specify which TestWidget's ButtonTwo text we want to change (otherwise, theoretically they could all change when we only want one to change).

    Since you seem to be trying to access an already defined function from your python code, all you need to do is to find the relevant root widget that it is contained in and use the address:

    Say the function was contained with TestWidget and you wanted to execute it from the non testwidget button to change testwidget button text, you would do something like this in the python class file:

    class PrimaryWidget(Layoutofyourchoice):
    
        def change_text(self):
           self.ids.test.ids.ButtonTwo.text = 'CHANGED TEXT'
    

    Then in your kv file, you would do:

    <PrimaryWidget>:
         BoxLayout:
             TestWidget:
                 id: Test
             Button:
                 on_press: root.change_text()
    

    I hope this helped you!