Search code examples
pythonpython-3.xkivykivy-language

Kivy - Setting event actions using dynamic classes


I'm currently trying to trigger events of some widgets nested in dynamic classes. To be more specific. This is an example kv file:

    <UserSelectionInput@BoxLayout>:
        orientation: 'horizontal'
        size_hint: None, 1
        spacing: 4

        lb_text: ''
        lb_id: 'user_selection_label'
        sp_values: '', ''
        sp_id: 'user_selection_spinner'

        Label:
            id: root.lb_id
            size_hint_x: 0.4
            text: root.lb_text
        Spinner:
            id: root.sp_id
            text: 'Select'
            values: root.sp_values

    <InnerBox@AnchorLayout>:
        anchor_x: 'center'
        anchor_y: 'center'

        BoxLayout:
            orientation: 'horizontal'
            size_hint: None, 1
            width: 2 * root.width / 3
            spacing: 1

            UserSelectionInput:
                width: root.width / 3
                sp_values: 'A', 'B', 'C'
                lb_text: 'Type'
                lb_id: 'label_1'
                sp_id: 'spinner_1'
            UserSelectionInput:
                width: root.width / 3
                sp_values: 'D', 'E', 'F', 'G'
                lb_text: 'Version'
                lb_id: 'label_2'
                sp_id: 'spinner_2'

    <MainContent>:
        rows: 3

        Label:
            text: "Some Text"
        GridLayout:
            cols: 1
        InnerBox:

What I want to do now is to use the 'on_text' event of the spinner inside the 'InnerBox' layout to call a function from the associated .py file. I'm not sure if this is the best way but in terms of reusability, I want to use the concept of dynamic classes for certain combinations of widgets.

Julz


Solution

  • Note: kv file - Assigning a value to id

    When assigning a value to id, remember that the value isn’t a string. There are no quotes:

    good -> id: user_selection_label or id: user_selection_spinner

    bad -> id: 'user_selection_label' or id: 'user_selection_spinner'

    Using on_text in class InnerBox()

    1) kv file - Dynamic class rule, UserSelectionInput

    • Create a new property associated with the text property of the Spinner

    Snippets

    <UserSelectionInput@BoxLayout>:
        text: user_selection_spinner.text
    
        ...
        Spinner:
            id: user_selection_spinner
            text: 'Select'
            values: root.sp_values
    

    2) kv file - Dynamic class rule, InnerBox

    • Use the on_text property event

    Snippets

    <InnerBox@AnchorLayout>:
        ...
    
        BoxLayout:
            ...
    
            UserSelectionInput:
                on_text:
                    print("UserSelectionInput.spinner_1: text=", self.text)
    
            UserSelectionInput:
                on_text:
                    print("UserSelectionInput.spinner_2: text=", self.text)
    

    Example

    main.py

    from kivy.base import runTouchApp
    from kivy.lang import Builder
    
    
    runTouchApp(Builder.load_string("""
    <UserSelectionInput@BoxLayout>:
        orientation: 'horizontal'
        size_hint: None, 1
        spacing: 4
    
        lb_text: ''
        sp_values: '', ''
        text: user_selection_spinner.text
    
        Label:
            id: user_selection_label
            size_hint_x: 0.4
            text: root.lb_text
        Spinner:
            id: user_selection_spinner
            text: 'Select'
            values: root.sp_values
    
    <InnerBox@AnchorLayout>:
        anchor_x: 'center'
        anchor_y: 'center'
    
        BoxLayout:
            orientation: 'horizontal'
            size_hint: None, 1
            width: 2 * root.width / 3
            spacing: 1
    
            UserSelectionInput:
                width: root.width / 3
                sp_values: 'A', 'B', 'C'
                lb_text: 'Type'
                on_text:
                    print("UserSelectionInput.spinner_1: text=", self.text)
    
            UserSelectionInput:
                width: root.width / 3
                sp_values: 'D', 'E', 'F', 'G'
                lb_text: 'Version'
                on_text:
                    print("UserSelectionInput.spinner_2: text=", self.text)
    
    <MainContent@GridLayout>:
        rows: 3
    
        Label:
            text: "Some Text"
        GridLayout:
            cols: 1
            InnerBox:
    
    MainContent:
    
    """))