lit
lit

Reputation: 460

Kivy Update Dynamic Label Text

My goal is to watch the number count on the Popup. I have a NumericProperty being loaded. However, The numbers do not change when callback is called. (I do not have any code in callback linking to the label.text)

Similar questions have been asked. But, I have been unable to see how they apply to this specific case. Similar Case

import kivy
kivy.require("1.7.0")

from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.properties import NumericProperty
from kivy.clock import Clock
from kivy.event import EventDispatcher

scoreInc = 0

class MyPopup(Popup):

    def show_popup(self):

        content = BoxLayout(orientation="vertical")

        self.incrementerFnc = Clock.schedule_interval(self.incrementer, .005)

        scoreLabel = Label(text=str(ins.a), id='scorelabel', font_size=20)

        content.add_widget(scoreLabel)

        mybutton = Button(text="Close", size_hint=(1,.20), font_size=20)
        content.add_widget(mybutton)

        mypopup = Popup(content = content,              
                title = "Score",     
                auto_dismiss = False,         
                size_hint = (.7, .5),         
                font_size = 20)
        mybutton.bind(on_press=mypopup.dismiss)  
        mypopup.open()

    def incrementer(self, dt):
        global scoreInc
        scoreInc += 1

        ins.a = scoreInc

        if(scoreInc >= 10):
            Clock.unschedule(self.incrementerFnc)
            print('quit')
        else:
            print('scoreInc', ins.a)    

class MyClass(EventDispatcher):
    a = NumericProperty(0)

def callback(instance, value):
    print('My callback is call from', instance)
    print('and the a value changed to', value)

ins = MyClass()
ins.bind(a=callback)


class MyApp(App):     

    def build(self):

        mypopup = MyPopup()

        return mypopup.show_popup()

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

Upvotes: 2

Views: 10336

Answers (2)

el3ien
el3ien

Reputation: 5405

I would take a different approach at this.
Instead of using globals, have the score as a property in a custom layout, and pass that to the popup.

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock


KV = '''

<MyPopup>:
    title: "Game over"
    score_label: score_label
    id: popup
    content: bl
    BoxLayout:
        id: bl
        Label:
            id: score_label
            text:"Your score is"
            font_size:20
        Button:
            text:"Close this!!"
            on_release: popup.dismiss()


MyLayout:

    orientation: "vertical"
    Label:
        text: "Type in score"
    TextInput:
        id: score_inp
    Button:
        text: "Open gameover popup"
        on_release:
            root.gameover_popup.open()
            root.gameover_popup.gameover(score_inp.text)

'''


class MyPopup(Popup):

    def gameover(self,score):
        self.iterations = int(score)
        self.score = 0
        self.event = Clock.schedule_interval(self.set_label,0.1)

    def set_label(self,dt):
        self.score += 1
        self.score_label.text = str(self.score)
        if self.score >= self.iterations:
            self.event.cancel()



class MyLayout(BoxLayout):

    def __init__(self,**kwargs):
        super(MyLayout,self).__init__(**kwargs) 
        self.gameover_popup = MyPopup()



class MyApp(App):

    def build(self):
        return Builder.load_string(KV)


MyApp().run()

Upvotes: 3

Peter Badida
Peter Badida

Reputation: 12169

You are missing an event that updates the text value of your scoreLabel which you need to handle in your MyClass, see below:

class MyClass(EventDispatcher):
    a = NumericProperty(0)
    def on_a(self, instance, value):
        app = App.get_running_app()
        app.scoreLabel.text = str(value)

when property a updates, on_a is triggered and then you can use it to update the scoreLabel value, otherwise it's not even connected. The line text = str(ins.a) takes the value from the ins.a and uses it i.e. 0 for you.

However, you'll need to access that scoreLabel somehow, which might be useful through e.g. App.get_running_app() where you can store the instance for later use:

    app = App.get_running_app()
    app.scoreLabel = Label(text=str(ins.a), id='scorelabel', font_size=20)

    content.add_widget(app.scoreLabel)

This way you can access it even in the on_a event later. Or use self and access the Popup directly with App.get_running_app().popup and then its content.

App.get_running_app() however might be not a preferable option sometimes, therefore you can use even globals, or some other way to store the instance e.g. inside some other class. If you have a Popup, that widget adds itself to the root Window for example and it's stored in:

Window -> children -> Popup -> content -> layout -> scoreLabel

but be careful with that because messing with the Window directly might have unfortunate results.

Upvotes: 4

Related Questions