Reputation: 35
In my application, I have multiple screens. Each screen corresponds to a class. Now I would like to display a property that was calculated in a certain class (screen) on another screen. Below is a simplified example to outline my problem. In the class WordComprehension, the NumericProperty count_r is incremented, every time the button is pressed. Now, I would like to display the result of this calculation in the ScoreScreen. Thanks for your suggestions. Here is the .py:
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import ObjectProperty
from kivy.properties import NumericProperty
class AppScreen(FloatLayout):
app = ObjectProperty(None)
class MainMenu(AppScreen):
pass
class ScoreScreen(AppScreen):
score = NumericProperty(0)
def get_score(self):
wordcomp = WordComprehension()
self.score = wordcomp.count_r
class WordComprehension(AppScreen):
count_r = NumericProperty(0)
count_w = NumericProperty(0)
def do_something(self):
self.count_r += 1
class InterfaceApp(App):
def build(self):
self.screens = {}
self.screens["wordcomp"] = WordComprehension(app=self)
self.screens["menu"] = MainMenu(app=self)
self.screens["score"] = ScoreScreen(app=self)
self.root = FloatLayout()
self.goto_screen("menu")
return self.root
def goto_screen(self, screen_name):
self.root.clear_widgets()
self.root.add_widget(self.screens[screen_name])
if __name__ == "__main__":
InterfaceApp().run()
and the .kv:
#:kivy 1.8.0
<MainMenu>:
BoxLayout:
orientation: 'vertical'
Label:
text: "Choose Category"
font_size: 30
Button:
text: 'Word Comprehension'
on_press: root.app.goto_screen("wordcomp")
Button:
text: 'Highscore'
on_press: root.app.goto_screen("score")
disabled: False
<ScoreScreen>:
BoxLayout:
orientation: 'vertical'
Button:
text: 'get score'
on_press: root.get_score()
Label:
text: "Word Comprehension right answers:" + str(root.score)
Button:
text: 'Main Menu'
on_release: root.app.goto_screen("menu")
<WordComprehension>:
BoxLayout:
orientation: 'vertical'
Label:
text: str(root.count_r)
Button:
text: 'Do something'
on_release: root.do_something()
Button:
text: 'Menu'
on_press: root.app.goto_screen("menu")
Upvotes: 2
Views: 4503
Reputation: 256
You can bind kivy properties to one another, so that when one changes so does the other. To do this you bind to the setter() function of the class. (http://kivy.org/docs/api-kivy.event.html)
Here is what you need to do:
1) Create a NumericProperty in the ScoreScreen for the count_r.
2) Bind the count_r NumericProperty in WordComprehension to the NumericProperty in ScoreScreen like so :
'''in class WordComprehension '''
self.bind(count_r=self.score_screen.setter('count_r')
Now the trick is that you need to have a reference to the ScoreScreen instance in your WordComprehension class. In my example, I assumed you have a reference to it in self.score_screen
. I will leave it up to you how you want to assign that reference.
Now whenever count_r is changed in WordComprehension, the setter function (which is essentially a setattr() ) gets called on the 'count_r' property of ScoreScreen.
Another thing: The line wordcomp = WordComprehension()
in get_score() is not referencing the same WordComprehension instance that you want. You are creating a new object of class WordComprehension and referencing it's count_r which will be it's default value.
EDIT1 Not sure if this is what you want but this code will make the score property update whenever the count_r property is changed:
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import ObjectProperty
from kivy.properties import NumericProperty
class AppScreen(FloatLayout):
app = ObjectProperty(None)
class MainMenu(AppScreen):
pass
class ScoreScreen(AppScreen):
count_r = NumericProperty(0)
score = NumericProperty(0)
# This is making a new WordComprehension object, and thus will not have
# the correct value of score. We no longer need this is we are binding properties
# together.
#def get_score(self):
# wordcomp = WordComprehension()
# self.score = wordcomp.count_r
class WordComprehension(AppScreen):
count_r = NumericProperty(0)
count_w = NumericProperty(0)
def do_something(self):
self.count_r += 1
class InterfaceApp(App):
def build(self):
self.screens = {}
self.screens["wordcomp"] = WordComprehension(app=self)
self.screens["menu"] = MainMenu(app=self)
self.screens["score"] = ScoreScreen(app=self)
self.root = FloatLayout()
self.goto_screen("menu")
# Bind the two properties together. Whenever count_r changes in the wordcomp
# screen, the score property in the score screen will reflect those changes.
self.screens["wordcomp"].bind(count_r=self.screens["score"].setter('score'))
return self.root
def goto_screen(self, screen_name):
self.root.clear_widgets()
self.root.add_widget(self.screens[screen_name])
if __name__ == "__main__":
InterfaceApp().run()
Upvotes: 4