radzak
radzak

Reputation: 3118

Kivy, Python - self-updating label text

I'm working on a project with my friend. My part of a job is to make a working and pretty-looking GUI... :) I'm pretty new to Kivy and even oop.

I encountered a problem and even after a solid research, when I found something that MAY be the solution to my problem, I don't know how to apply it to my code.

Let's get to the point. I've created an app consisted of several screens. On the main screen, there are 3 bigger sections:

  1. GridLayout where main buttons are stored
  2. ScrollView initially empty
  3. GridLayout where some "action buttons" are stored (Update, Download etc.)

I'm using kivy language to create them and add them to the screen!

My problem is I want to have self-updating label text in my 1st section. By clicking a 3rd section button I want to update the text. 3rd section GridLayout has an individual class in .py file where I have some functions which I binded to the keys.

<MainScreen>:
name: 'main'

GridLayout:
    cols: 1
    spacing: 10

    GridLayout:
        id: menu_bar
        cols: 6
        MenuButton:
        MenuButton:
        Label:
           text: "I want to be auto-updated"

    ScrollView:
        (...)

    MainScreenButtons:
        id: main_buttons
        cols:4

        MainScreenButton:
            text: "UPDATE"
            on_release:
                (...)
        MainScreenButton:
            text: "DOWNLOAD"
            on_release:
                (...)
        MainScreenButton:
            text: "PAUSE"
            on_release:
                (...)

In python file I have created MainScreenButtons class, I have all the functions I use with these keys wrapped up in there.

class MainScreen(Screen):
    pass

class MainScreenButtons(GridLayout):
    def download(self):
         pass
    (...)

Basically, I want to add a function to MainScreenButtons class which updates some variable and I want to call it when one of these 3 buttons are clicked. I don't know how to update the label's text, because it's not even mentioned in python file, but they are all stored in MainScreen class. I can't come up with any working idea, I'm pretty confused, please help me out :)

I am aware of that my explanation might be a bit insufficient, but I did my best to simplify it as much as I can.

Upvotes: 0

Views: 888

Answers (2)

Yoav Glazner
Yoav Glazner

Reputation: 8066

You should just use kivy's builtin binding with the kv lang.

Here is your code slightly modified:

from kivy.properties import StringProperty

class MainScreen(Screen):
    pass

class MainScreenButtons(GridLayout):

    some_update = StringProperty("default value")

    def download(self):
        self.some_update = "Downloading now...

here is the kv file:

<MainScreen>:
    name: 'main'

GridLayout:
    cols: 1
    spacing: 10

    GridLayout:
        id: menu_bar
        cols: 6
        MenuButton:
        MenuButton:
        Label:
           text: main_buttons.some_update #this binding will happen here

    ScrollView:
        (...)

    MainScreenButtons:
        id: main_buttons
        cols:4
        some_update: "" #our new propery to be used from the python file
        MainScreenButton:
            text: "UPDATE"
            on_release:
                (...)
        MainScreenButton:
            text: "DOWNLOAD"
            on_release:
                (...)
        MainScreenButton:
            text: "PAUSE"
            on_release:
                (...)

Upvotes: 0

Henrique Barcelos
Henrique Barcelos

Reputation: 7900

This problem could be solved with the Observer pattern.

Your 3rd section button is the subject ("observed") object. Your label in the 1st section is the observer object.

Whenever the subject is updated (ie, it's clicked), it should notify it's observers in order to allow them to change their state (ie, the displayed text) too.

I'll keep this as a simple code example, please adapt it to your needs:

class Button:
    def __init__(self):
        self._observers = []

    def attach(self, obj):
        self._observers.append(obj)

    def detach(self, obj):
        self._observers.remove(obj)

    def notifyAll(self, msg):
        for o in self._observers:
            o.update(msg);

    # this is the method that will be called whenever you click the button
    def onClickHandler(self, evt):
        # do whatever you should do...
        self.notifyAll("Clicked!")

class Label:
    def update(self, msg):
        # here you update your text based on the message you receive

Then you do:

label = Label("Some text")
button = Button("Click")

button.attach(label);

# when you click the button, the label will be notified it 
# was clicked and will update itself

This is the general idea. Adapt it to your needs.

Upvotes: 0

Related Questions