kivy / kivy

Open source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS
https://kivy.org
MIT License
17.57k stars 3.06k forks source link

StringProperty() does not update Label Text. #5842

Closed labanau closed 6 years ago

labanau commented 6 years ago

Versions

Description

I have two different files, "main.kv" and "GameStatusTracker.py". I am using a screen manager to change through screens. Now when I enter the player name and select the toggle button, the values are being past correctly to other functions. The problem I have, after calling a request to the specific websites, getting back the data and assigning that data to the "StringProperty" variable does not update the label text. I have tried many different things and changes, nothing seems to work. However, I did notice one strange bug. While in the "SecondScreen" and I have my String property set to:

rating_label = StringProperty(rebind = true)

Later on in the function "lol"(after so many testings I have just left it for now as lol, will change later on if I manage to fix it.) the self.rating_label value is set to the value which I get from the website. Which is "1.285". Now if I call a getter function it still returns the value "loll" which I have set in the init function. code below. Any help? If needed I can post the whole code.

Code and Logs


class FortniteScreen(Screen):
    rating_label = StringProperty(rebind=True)
    print("Fortnite_Screen Called.")

    def __init__(self, **kwargs):
        super(FortniteScreen, self).__init__(**kwargs)
        self.rating_label = "loll"

    def lol(self,name):
        get_stats_fortnite1 = Fortnite()
        get_stats_fortnite1.playerGet(name)
        self.saved_stats = str(get_stats_fortnite1.playerStats())
        self.rating_label = self.saved_stats
        print("Called Fortnite Class--> " + self.rating_label) # <- at this point I get that the value is 1.285

    def get_rating(self):
        print("Called Get_Rating -->" + self.rating_label) # <-- When I call this function after a button press, the value is still "loll"
        return self.rating_label

#in .kv file <FortniteScreen>:
        Label:
            text: "Rating:"
        Label:
            id: rating_label
            text: root.rating_label
tshirtman commented 6 years ago

Hm, is there anything special about how you get/update the value from your request? using multiprocessing or some other magic maybe? it looks as if you had two instances of your screen, one updated and one with the default value, maybe print self's value in the two places where you see the different values, to be sure that's the same python object? It could help if you shared a complete example we can run to reproduce, it doesn't need to (and shouldn't) be your full current program, but as short as possible while still showing the issue would be nice.

labanau commented 6 years ago

Ok so this is the KV file(I have deleted parts which I do not think are needed):

# File name: main.kv
#: import SlideTransition kivy.uix.screenmanager.SlideTransition

ScreenManagement:
    transition: SlideTransition()

        # I am not sure if I need the part below here|
    main_screen: main_screen
    fortnite_screen: fortnite_screen
    csgo_screen: csgo_screen
    pubg_screen: pubg_screen

    MainScreen:
        id: main_screen
    FortniteScreen:
        id: fortnite_screen
    CsgoScreen:
        id: csgo_screen
    PubgScreen:
        id: pubg_screen
#The main screen, toggle buttons selects the game, the input gets the player name

<MainScreen>:
    name: "main"
    AnchorLayout:
        Image:
            allow_stretch: True
            color: 1,1,1,0.2
            source: 'bcimage.jpg'
            keep_ratio: False
        AnchorLayout:
            anchor_x: 'center'
            anchor_y: 'top'
            BoxLayout:
                orientation: 'vertical'
                GridLayout:
                    id: _game_select
                    size_hint: 1,None
                    height: 150
                    rows: 2
                    BoxLayout:
                        orientation: 'horizontal'
                        spacing: 4
                        ToggleButton:
                            id: _pubg_button
                            pubg_button: _pubg_button
                            group: 'GameSelect'
                            background_normal: 'pubg.jpg' 
                            background_down: 'pubg_selected.jpg'
                            on_state: root.pubg_selected(*args)

                        ToggleButton:
                            id: _fortnite_button
                            fortnite_button: _fortnite_button
                            group: 'GameSelect'
                            background_normal: 'fortnite.jpg'
                            background_down: 'fortnite_selected.jpg'
                            on_state: root.fortnite_selected(*args)

                        ToggleButton:
                            id: _csgo_button
                            csgo_button: _csgo_button
                            group: 'GameSelect'
                            background_normal: 'csgo.jpg'
                            background_down: 'csgo_selected.jpg'
                            on_state: root.csgo_selected(*args)

                    BoxLayout:
                        orientation: 'horizontal'
                        search: _text_input
                        size_hint: 0.25,0.25
                        TextInput:
                            id: _text_input
                            text: " "
                            multiline: False
                        Button:
                            text: 'Search'
                            on_release:
                                app.root.current = "fortnite"
                                root.manager.transition.direction = "left"
                                root.on_press( _text_input.text)
                Widget:
        GridLayout:
            cols: 4
            rows: 10
            Label:
                text: "GameTracker"
            Label:
                text: "By: Rokas L."

<FortniteScreen>:
    name: "fortnite"
    Image:
        allow_stretch: True
        color: 1,1,1,0.2
        source: 'bcimage.jpg'
        keep_ratio: False
    GridLayout:
        cols: 6
        rows: 8
        Label:
            text: "Rating:"
        Label:
            id: rating_label
            text: root.rating_label
        #I deleted other labels as they are not needed.
        Button:
            font_size: 22
            text: "Back"
            size_hint: 1,1
            on_release:
                app.root.current = "main"
                root.manager.transition.direction = "right"
        Button:
            font_size: 22
            text: "Show Stats"
            size_hint: 1,1
            on_press:
                root.get_rating()

Now for the Python Code:

from kivy.app import App
#kivy.require("1.10.0")
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
from kivy.properties import NumericProperty, ListProperty, StringProperty, ObjectProperty
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
import json
import requests

class Fortnite():
    def __init__(self, platform = 'pc'):
        self.api_key = '5f1c8da2-a843-479e-84af-4e2be4a50a95'
        self.platform = platform
        self.fortnite_url = 'https://api.fortnitetracker.com/v1/profile/pc/'
        self.headers = {
            'content-type': "application/json",
            'TRN-API-KEY': self.api_key,
          }

    def playerGet(self, player_handle):

        response = requests.request("GET",'https://api.fortnitetracker.com/v1/profile/pc/' + str(player_handle.strip(" ")), headers=self.headers)
        data = json.loads(response.text)

        self.rating = data['stats']['p2']['trnRating']['displayValue']
        self.score = data['stats']['p2']['score']['displayValue']
        self.top1 = data['stats']['p2']['top1']['displayValue']
        self.top10 = data['stats']['p2']['top10']['displayValue']
        self.top25 = data['stats']['p2']['top25']['displayValue']
        self.kdRatio = data['stats']['p2']['kd']['displayValue']
        self.winRatio = data['stats']['p2']['winRatio']['displayValue']
        self.matches = data['stats']['p2']['matches']['displayValue']
        self.kills = data['stats']['p2']['kills']['displayValue']
        self.kpg = data['stats']['p2']['kpg']['displayValue']
        self.scorePerMatch = data['stats']['p2']['scorePerMatch']['displayValue']

    def playerStats(self):
        return self.rating

class MainScreen(Screen):

    def pubg_selected(self, instance, value):
        if value == 'down':
            self.game = "pubg"
        else:
            self.game = "None"

    def fortnite_selected(self, instance, value):
        if value == 'down':
            self.game = "fortnite"
        else:
            self.game = "None"

    def csgo_selected(self, instance, value):
        if value == 'down':
            self.game = "csgo"
        else:
            self.game = "None"

    def on_press(self, entered_text):
        self.entered_text = entered_text
        print("The entered name is: " + self.entered_text + " selected game is: " + self.game)

        sc_changed = FortniteScreen()# Here after the "search is pressed and  selected game" is selected I call a function from Fortnite Class to update the rating_label value
        sc_changed.lol(self.entered_text)

class FortniteScreen(Screen):
    rating_label = StringProperty(rebind=True)
    print("Fortnite_Screen Called.")

    def __init__(self, **kwargs):
        super(FortniteScreen, self).__init__(**kwargs)
        self.rating_label = "loll"

    def lol(self,name):
        get_stats_fortnite1 = Fortnite()
        get_stats_fortnite1.playerGet(name)
        self.saved_stats = str(get_stats_fortnite1.playerStats())
        self.rating_label = self.saved_stats
        print("Called Fortnite Class--> " + self.rating_label)

    def get_rating(self):
        print("Called Get_Rating -->" + self.rating_label)
        return self.rating_label

class CsgoScreen(Screen):
    pass

class PubgScreen(Screen):
    pass

#Now as I see it, this could interfere?  Below class ScreenManagement
class ScreenManagement(ScreenManager):
    main_screen = ObjectProperty(None)
    fortnite_screen = ObjectProperty(None)
    csgo_screen = ObjectProperty(None)
    pubg_screen = ObjectProperty(None)

MainFile = Builder.load_file("main.kv")

class MainApp(App):

    def build(self):
        return MainFile

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

If I need to update something(as you see that I do not need to use something or is it bad, please leave a feedback too.)

tshirtman commented 6 years ago

Ok, so you create a new FortniteScreen and call its lol method in on_press, that's your issue, you want to call the lol method of you existing FortniteScreen (created in the root rule, with id fortnite_screen.

change the code in on_press to:

App.get_running_app().root.ids.fortnite_screen.lol(entered_text)

and it should work.

support[bot] commented 6 years ago

👋 We use the issue tracker exclusively for bug reports and feature requests. However, this issue appears to be a support request. Please use our support channels to get help with the project.

If you're having trouble installing Kivy, make sure to check out the installation docs for Windows, Linux and macOS.

Let us know if this comment was made in error, and we'll be happy to reopen the issue.