Search code examples
pythonkivykivy-language

Insert a piece of code in the text of a Label that involves variables inside kv lang


I need to insert a piece of code in the text of a Label that involves variables inside kv lang as shown below:

import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang.builder import Builder
from kivy.core.window import Window

Window.size=(200,200)

Builder.load_string("""
<Screen>
    BoxLayout:
        orientation:'vertical'
        size:root.width,root.height
        Label:
            id:label
            text:'Nothing'
        Button:
            id:button
            text:'Insert'
            on_release: root.insert_text()
""")

class Screen(Widget):
    def insert_text(self):
        self.ids.label.text='Something' if button.text=='Insert' else 'Nothing' #Label should say "Something" if Button's text says 'Insert'
class App(App):
    def build(self):
        return Screen()

if __name__=='__main__':
    App().run()

When running this code I get the error: NameError: name 'button' is not defined

How can I avoid this error and have the entered code work within kv lang? I already tried putting self.ids.button.text instead of button.text and despite not getting the error, it doesn't work inside the application either.

Edit: Also tried insert button.text as a raw string but kv lang just ignored it.


Solution

  • If you want Label text to change without a Button press, then you probably want to use a Property. You can reference a Property in kv and any changes to that Property will trigger evaluation where that Property is used. So, here is a modified version of your code that uses a Property named follow_changes that controls whether the Label text follows the Button text:

    from kivy.app import App
    from kivy.properties import BooleanProperty
    from kivy.uix.widget import Widget
    from kivy.lang.builder import Builder
    from kivy.core.window import Window
    
    Window.size = (200, 200)
    
    Builder.load_string("""
    <Screen>
        BoxLayout:
            orientation:'vertical'
            size:root.width,root.height
            Label:
                id:label
                text: 'Something' if root.follow_changes and button.text == 'Insert' else 'Nothing'  # use follow_changes Property
            Button:
                id:button
                text:'Insert'
                on_release:
                    root.follow_changes = True  # turn on following_changes
            Button:
                text: "Change Button Text"
                on_release:
                    button.text = 'Abba'
    """)
    
    class Screen(Widget):
        follow_changes = BooleanProperty(False)  # Property to control Label text
    
    class App(App):
        def build(self):
            return Screen()
    
    if __name__=='__main__':
        App().run()