Reputation: 854
I am currently building an app for self measurement. I've faced the following problem : I want to have a result screen, with progress bars for my achievements. So far it looks like this:
<ResultScreen>:
BoxLayout:
Button:
text: 'Назад, к музыке'
on_press: root.manager.current = 'music'
ProgressBar:
max : 1000
value : root.manager.get_screen('music').slider.value
The problem is, root.manager
works fine when applied to the Button
and returns to the given screen. However in ProgressBar
it appears to be None
and returns the following error:
AttributeError: 'NoneType' object has no attribute 'get_screen'
What is wrong?
The full code:
main.py:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import (
NumericProperty, ReferenceListProperty, ObjectProperty
)
from kivy.vector import Vector
from kivy.clock import Clock
from kivy.uix.screenmanager import ScreenManager, Screen
class PongScreen(Screen):
pass
class MusicScreen(Screen):
pass
class DiscreteScreen(Screen):
pass
class ResultScreen(Screen):
pass
class PongApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(PongScreen(name='menu'))
sm.add_widget(MusicScreen(name='music'))
sm.add_widget(DiscreteScreen(name='discrete'))
sm.add_widget(ResultScreen(name='result'))
return sm
if __name__ == '__main__':
PongApp().run()
pong.kv:
#:kivy 1.0.9
#:import Factory kivy.factory.Factory
<MusicScreen>:
BoxLayout:
Button:
text: 'Назад в меню'
on_press: root.manager.current = 'menu'
Button:
text: 'Дальше, к дискретке'
on_press: root.manager.current = 'discrete'
Slider:
id: slider
min: 0
max: 20
step: 1
orientation: 'vertical'
Label:
text: 'Тактов выучено\n' + str(slider.value)
CheckBox:
id : new_song_checkbox
Label:
text : 'Новую песню выучил?\n' + str(new_song_checkbox.active)
CheckBox:
id : music_pleasure_checkbox
Label:
text : 'Доволен ли исполнением\n' + str(music_pleasure_checkbox.active)
<DiscreteScreen>:
BoxLayout:
Button:
text: 'В меню'
on_press: root.manager.current = 'menu'
Button:
text: 'Назад, к музыке'
on_press: root.manager.current = 'music'
Slider:
id: slider
min: 0
max: 180
step: 15
orientation: 'vertical'
Label:
text: 'Минут на код затрачено\n' + str(slider.value)
CheckBox:
id : article_checkbox
Label:
text : 'Статью прочитал?\n' + str(article_checkbox.active)
CheckBox:
id : lecture_checkbox
Label:
text : 'Посмотрел ли лекцию?\n' + str(lecture_checkbox.active)
<DiscreteScreen>:
BoxLayout:
Button:
text: 'В меню'
on_press: root.manager.current = 'menu'
Button:
text: 'Назад, к музыке'
on_press: root.manager.current = 'music'
Button:
text: 'Дальше, к результатам'
on_press: root.manager.current = 'result'
Slider:
id: slider
min: 0
max: 180
step: 15
orientation: 'vertical'
Label:
text: 'Минут на код затрачено\n' + str(slider.value)
CheckBox:
id : article_checkbox
Label:
text : 'Статью прочитал?\n' + str(article_checkbox.active)
CheckBox:
id : lecture_checkbox
Label:
text : 'Посмотрел ли лекцию?\n' + str(lecture_checkbox.active)
<ResultScreen>:
BoxLayout:
Button:
text: 'Назад, к музыке'
on_press: root.manager.current = 'music'
ProgressBar:
max : 1000
value : root.manager.get_screen('music').slider.value
<PongScreen>:
BoxLayout:
Button:
text: 'К музыке'
on_press: root.manager.current = 'music'
Button:
text: 'К дискретке'
on_press: root.manager.current = 'discrete'
Button:
text: 'К результатам'
on_press: root.manager.current = 'result'
Button:
text: 'Выход'
on_press: app.stop()
Upvotes: 0
Views: 230
Reputation: 2908
First of all value : root.manager.get_screen('music').slider.value
is wrong because root.manager.get_screen('music')
is supposed to be a Screen
object and by default it doesn't have (also not in your code) any prop. slide
.
Perhaps you mean value : root.manager.get_screen('music').ids.slider.value
. But this will not solve your problem. Let's try to analyze the problem in simple way.
When the method run
is called, the kv-rules are applied (by method load_kv
) first then method build
is called. In the method build
you defined ScreenManager
first thereafter added the Screens
and described the screens in kvlang
. Now when it encounters your .kv
file and looks for root.manager
(in value : root.manager.get_screen('music').ids.slider.value
) it finds None
(the default value, as it has not yet been added to ScreenManager
, defined in your build
method). That's the reason behind the AttributeError
.
Now to solve this issue one of many ways could be,
on_enter
etc. as,<ResultScreen>:
on_enter: pb.value = self.manager.get_screen('music').ids.slider.value
BoxLayout:
Button:
text: 'Назад, к музыке'
on_press: root.manager.current = 'music'
ProgressBar:
id: pb
max : 1000
ProgressBar:
id: pb
max : 1000
value : root.manager.get_screen('music').ids.slider.value if root.manager is not None else 0
root
(i.e. ScreenManager
here) entirely in kvlang
.Other ways could be creating a property for slide.value
in the associate class; manage it in the build
method etc.
Upvotes: 0