Roelof Coertze
Roelof Coertze

Reputation: 586

Appending and removing code elements within Kivy language on button click

I have written a Kivy GUI that consists of various buttons and nested layouts. I want to be able to, on a click of a button, append a section of code n number of times within one of these layouts, specifically the scroll layout. Since I have am very new to Kivy and since I cannot seem to find a tutorial on this matter, I am presenting it here.

Here is the Python code:

import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.widget import Widget


class Interface(Widget):
    pass

class GUI(App):
    def build(self):
        return Interface()

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


And the total Kivy code:

<Interface>:
    GridLayout:
        padding:0
        size: root.width, root.height
        cols:1
        #Top buttons
        GridLayout:
            size_hint: 1, 0.07
            padding:0
            cols:1
            Button:
                text:"Add Phase"
        #Chart areas
        ScrollView:
            do_scroll_y:False
            BoxLayout:
                orientation: "vertical"
                size_hint_x: None
                width: self.minimum_width
                GridLayout:
                    size_hint_x: None
                    width: self.minimum_width
                    cols:20



                    #Phase template
                    GridLayout:
                        width: 200
                        size_hint_x: None
                        cols:1
                        TextInput:
                            size_hint: 1, 0.06
                            halign: 'center'
                            hint_text:"Phase"
                        TextInput:
                            size_hint: 1, 0.06
                            halign: 'center'
                            hint_text:"Step"
                        Button:
                            size_hint:1, 0.07
                            text:"Add Step"
                        GridLayout:
                            cols:20

                            #Step template
                            GridLayout:
                                width: 100
                                size_hint_x: None
                                cols:1
                                TextInput:
                                    size_hint: 1, 0.06
                                    halign: 'center'
                                    hint_text:"Var1"
                                TextInput:
                                    size_hint: 1, 0.06
                                    halign: 'center'
                                    hint_text:"Var2"
                                Button:
                                    background_normal: ''
                                    background_color: 0.28,0.59,0.72,1
                                    text:"Test"
                                Button:
                                    size_hint:1, 0.07
                                    text:"Delete"


                        Button:
                            background_color: 0.8,0,0,1
                            size_hint:1, 0.07
                            text:"Delete"


You will see in the Kivy code that these is a commented secion called #Phase template. Basically on pressing the button Add Phase, this entire section and its children elements should be appended in the immediate parent GridLayout.

Here you can press the Add Phase button: Here you can press the Add Phase button:

Which will result in this:

Which will result in this

And then finally, pressing the Delete button should remove that specific appended section of code.

Again, no idea how to approach this from the Kivy language, which seems a bit rigid to work with. But I am sure what I want to do can be accomplished.

Upvotes: 0

Views: 103

Answers (1)

John Anderson
John Anderson

Reputation: 39052

One way to accomplish that is to create a Phase class, and add a kv rule for building instances of Phase. Then, in kv, you can use Factory.Phase() to create new instances.

Modify your kv as:

#:import Factory kivy.factory.Factory
<Interface>:
    GridLayout:
        padding:0
        size: root.width, root.height
        cols:1
        #Top buttons
        GridLayout:
            size_hint: 1, 0.07
            padding:0
            cols:1
            Button:
                text:"Add Phase"
                on_release: grid.add_widget(Factory.Phase())  # this adds another Phase
        #Chart areas
        ScrollView:
            do_scroll_y:False
            BoxLayout:
                orientation: "vertical"
                size_hint_x: None
                width: self.minimum_width
                GridLayout:
                    id: grid  # added id to identify where to add new Phase instances
                    size_hint_x: None
                    width: self.minimum_width
                    cols:20

                    # initial Phase instance
                    Phase:

#Phase template
<Phase@GridLayout>:
    width: 200
    size_hint_x: None
    cols:1
    TextInput:
        size_hint: 1, 0.06
        halign: 'center'
        hint_text:"Phase"
    TextInput:
        size_hint: 1, 0.06
        halign: 'center'
        hint_text:"Step"
    Button:
        size_hint:1, 0.07
        text:"Add Step"
    GridLayout:
        cols:20

        #Step template
        GridLayout:
            width: 100
            size_hint_x: None
            cols:1
            TextInput:
                size_hint: 1, 0.06
                halign: 'center'
                hint_text:"Var1"
            TextInput:
                size_hint: 1, 0.06
                halign: 'center'
                hint_text:"Var2"
            Button:
                background_normal: ''
                background_color: 0.28,0.59,0.72,1
                text:"Test"
            Button:
                size_hint:1, 0.07
                text:"Delete"


    Button:
        background_color: 0.8,0,0,1
        size_hint:1, 0.07
        text:"Delete"
        on_release: root.parent.remove_widget(root)  # delete this Phase

Key points are the <Phase@GridLayout> rule, the new grid id, and the use of Factory in the Add Phase Button.

Upvotes: 1

Related Questions