Search code examples
pythonclassoopkivykivy-language

Kivy - Can't change .text with id


I am trying to change the text of a label using an id, I tried it with stringProperty, with objectProperty without any properties. There has to be something I am missing in my code because it simply does not work whatever I try and any help would be greatly appreciated.

This bit of code is a simple screen with 2 buttons, one for going to the other screen and one for changing the label

from kivy.app import *
from kivy.uix.button import *
from kivy.graphics import *
from kivy.uix.widget import *
from kivy.uix.label import *
from kivy.uix.floatlayout import *
from kivy.uix.boxlayout import *
from kivy.uix.relativelayout import *
from kivy.uix.scrollview import ScrollView
from kivy.properties import ListProperty, StringProperty,ObjectProperty
from kivy.uix.screenmanager import ScreenManager,Screen
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.gridlayout import GridLayout

class WindowManager(ScreenManager):
    pass

class Name(FloatLayout):
    def __init__(self, **kwargs):
        super(Name, self).__init__(**kwargs)
    def changeName(self):
        print(self.ids)
        self.name = self.ids.nameOfSong.text
        print(self.name)
        self.ids.nameOfSong.text = 'name'
        self.name = self.ids.nameOfSong.text
        print(self.name)

class MainWindow(Screen):
    def __init__(self, **kwargs):
        super(MainWindow, self).__init__(**kwargs)
        self.pos = (0, 0)
        self.size = (1,1)
        self.z = Name()
        self.add_widget(self.z)
    def swap(self):
        Name().changeName()
class SecondWindow(Screen,BoxLayout):
    def __init__(self, **kwargs):
        super(SecondWindow, self).__init__(**kwargs)

class langApp(App):
    def build(self):
        sm = ScreenManager()
        sm.add_widget(MainWindow(name='main'))
        sm.add_widget(SecondWindow(name='second'))
        return sm

Builder.load_file("kiv.kv")
if __name__ == '__main__':
    langApp().run()

My kiv.kv file, most of it is not connected to the problem (I think)

#:kivy 1.11.1
WindowManager:
    MainWindow:
    SecondWindow:

<MainWindow>:
    name: "main"
    FloatLayout:
        pos: 0,0
        size: root.width,root.height
        Button:
            on_release:
                root.manager.transition.direction = 'left'
                app.root.current = "second"
            text: 'Stop'
            pos_hint: {'x':.45,'y':.1}
            size_hint: .1,.1
        Button:
            on_press: root.swap()
            text: 'Next'
            pos_hint: {'x':.65,'y':.1}
            size_hint: .1,.1

<SecondWindow>:
    name: "second"
    FloatLayout:
        pos: 0,0
        size: root.width,root.height
        Button:
            on_release:
                root.manager.transition.direction = 'right'
                app.root.current = "main"
            text: 'Stop'
            pos_hint: {'x':.45,'y':.1}
            size_hint: .1,.1

<Name>:
    Label:
        text: nameOfSong
        font_size: 20
        size_hint: None, None
        pos_hint: {'x': 0.435, 'y': 0.25}

Solution

  • A few problems with your code:

    First, your code as posted dos not run. The line in your kv:

    text: nameOfSong
    

    is illegal.

    Second, the code:

    def swap(self):
        Name().changeName()
    

    is creating a new instance of Name and calling changeName() on that new instance. However, that new instance is not the one that is displayed in your GUI.

    To fix that, you just need to call changeName() on the instance of Name that is in your GUI. Conveniently, you have saved a reference to the correct instance with the line:

    self.z = Name()
    

    So, you can change the swap() method to use that instance of Name:

    def swap(self):
        self.z.changeName()
    

    The other problem is that the changeName() method tries to use a non-existent id nameOfSong. To fix that (and to make your posted code runnable), just change the <Name> rule in your kv to define that id:

    <Name>:
        Label:
            id: nameOfSong
            text: 'Some Name'
            font_size: 20
            size_hint: None, None
            pos_hint: {'x': 0.435, 'y': 0.25}
    

    On an unrelated note, your code is building the App GUI twice. The line:

    Builder.load_file("kiv.kv")
    

    is building the GUI from the lines:

    WindowManager:
        MainWindow:
        SecondWindow:
    

    and your python code is building it again here:

    def build(self):
        sm = ScreenManager()
        sm.add_widget(MainWindow(name='main'))
        sm.add_widget(SecondWindow(name='second'))
        return sm
    

    You can delete those three lines from your kv file.