Reputation: 11
I'm completely new to kivy. The app has two screens - CalculateScreen and ResultScreen. ScreenManager provides switching between screens. CalculateScreen takes five values from TextInput: start_distance, finish_distance, start_gasoline, added_fuel, normal_consumption. Method counting returns three values - day_distance, daily_consumption, gasoline_left, which must be passed to appopriate text Labels of the ResultScreen on pressing "Calculate" button: day_distance_result, daily_consumption_result, gasoline_after_result. I tryed to do this by calling set_values method on changing screens but it doesn't work in appropriate way:
Traceback (most recent call last):
File "mainlogic.py", line 105, in <module>
MyApp().run()
File "C:\Users\Anna\project\lib\site-packages\kivy\app.py", line 950, in run
runTouchApp()
File "C:\Users\Anna\project\lib\site-packages\kivy\base.py", line 582, in runTouchApp
EventLoop.mainloop()
File "C:\Users\Anna\project\lib\site-packages\kivy\base.py", line 347, in mainloop
self.idle()
File "C:\Users\Anna\project\lib\site-packages\kivy\base.py", line 391, in idle
self.dispatch_input()
File "C:\Users\Anna\project\lib\site-packages\kivy\base.py", line 342, in dispatch_input
post_dispatch_input(*pop(0))
File "C:\Users\Anna\project\lib\site-packages\kivy\base.py", line 248, in post_dispatch_input
listener.dispatch('on_motion', etype, me)
File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
File "C:\Users\Anna\project\lib\site-packages\kivy\core\window\__init__.py", line 1412, in on_motion
self.dispatch('on_touch_down', me)
File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
File "C:\Users\Anna\project\lib\site-packages\kivy\core\window\__init__.py", line 1428, in on_touch_down
if w.dispatch('on_touch_down', touch):
File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
File "C:\Users\Anna\project\lib\site-packages\kivy\uix\screenmanager.py", line 1198, in on_touch_down
return super(ScreenManager, self).on_touch_down(touch)
File "C:\Users\Anna\project\lib\site-packages\kivy\uix\widget.py", line 545, in on_touch_down
if child.dispatch('on_touch_down', touch):
File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
File "C:\Users\Anna\project\lib\site-packages\kivy\uix\relativelayout.py", line 297, in on_touch_down
ret = super(RelativeLayout, self).on_touch_down(touch)
File "C:\Users\Anna\project\lib\site-packages\kivy\uix\widget.py", line 545, in on_touch_down
if child.dispatch('on_touch_down', touch):
File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
File "C:\Users\Anna\project\lib\site-packages\kivy\uix\widget.py", line 545, in on_touch_down
if child.dispatch('on_touch_down', touch):
File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
File "C:\Users\Anna\project\lib\site-packages\kivy\uix\behaviors\button.py", line 151, in on_touch_down
self.dispatch('on_press')
File "kivy\_event.pyx", line 705, in kivy._event.EventDispatcher.dispatch
File "kivy\_event.pyx", line 1248, in kivy._event.EventObservers.dispatch
File "kivy\_event.pyx", line 1132, in kivy._event.EventObservers._dispatch
File "C:\Users\Anna\project\lib\site-packages\kivy\lang\builder.py", line 57, in custom_callback
exec(__kvlang__.co_value, idmap)
File "C:\Users\Anna\project\kivy-project\my.kv", line 72, in <module>
on_press: root.set_values()
File "mainlogic.py", line 55, in set_values
result_screen.ids.day_distance_result.text = self.day_distance
AttributeError: 'CalculateScreen' object has no attribute 'day_distance'
Here is my main.py file.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty, StringProperty
class CalculateScreen(Screen):
start_distance = ObjectProperty()
finish_distance = ObjectProperty()
start_gasoline = ObjectProperty()
added_fuel = ObjectProperty()
normal_consumption = ObjectProperty()
def counting(self, start_distance, finish_distance, start_gasoline, added_fuel, normal_consumption):
if self.added_fuel == 0:
day_distance = str(finish_distance-start_distance)
daily_consumption = str((int(day_distance)*normal_consumption)/100)
gasoline_left = str(start_gasoline-float(daily_consumption))
else:
day_distance = str(finish_distance-start_distance)
daily_consumption = str((float(day_distance)*normal_consumption)/100)
gasoline_left = str((start_gasoline+added_fuel)-float(daily_consumption))
return day_distance, daily_consumption, gasoline_left
def calculations(self):
try:
start_distance = float(self.start_distance.text)
finish_distance = float(self.finish_distance.text)
start_gasoline = float(self.start_gasoline.text)
added_fuel = float(self.added_fuel.text)
normal_consumption = float(self.normal_consumption.text)
except:
start_distance = 0
finish_distance = 0
start_gasoline = 0
added_fuel = 0
normal_consumption = 0
self.counting(start_distance, finish_distance, start_gasoline, added_fuel, normal_consumption)
def set_values(self):
result_screen = self.manager.get_screen("result")
result_screen.ids.day_distance_result.text = self.day_distance
result_screen.daily_consumption_result.text = self.daily_consumption
result_screen.gasoline_after_result.text = self.gasoline_left
class ResultScreen(Screen):
day_distance_result = ObjectProperty()
daily_consumption_result = ObjectProperty()
gasoline_after_result = ObjectProperty()
class Manager(ScreenManager):
screen_one = ObjectProperty(None)
screen_two = ObjectProperty(None)
class MyApp(App):
def build(self):
m = Manager()
return m
if __name__=='__main__':
MyApp().run()
Here is my my.kv file.
<Manager>:
id: screen_manager
screen_one: screen_one
screen_two: screen_two
CalculateScreen:
id: screen_one
name: "calculator"
manager: screen_manager
ResultScreen:
id: screen_two
name: "result"
manager: screen_manager
<CalculateScreen>
name: "calculator"
start_distance: start_distance
finish_distance: finish_distance
start_gasoline: start_gasoline
added_fuel: added_fuel
normal_consumption: normal_consumption
BoxLayout:
orientation: 'vertical'
padding: 20
spacing: 10
BoxLayout:
orientation: 'vertical'
Label:
text: "Start distance"
TextInput:
id: start_distance
BoxLayout:
orientation: 'vertical'
Label:
text: "Final distance"
TextInput:
id: finish_distance
BoxLayout:
orientation: 'vertical'
Label:
text: "Fuel before leaving"
TextInput:
id: start_gasoline
BoxLayout:
orientation: 'vertical'
Label:
text: "Refuelling"
TextInput:
id: added_fuel
BoxLayout:
orientation: 'vertical'
Label:
text: "Normal consumption"
TextInput:
id: normal_consumption
Button:
text:'Calculate'
on_press: root.calculations()
on_press: root.set_values()
on_release: root.manager.current = "result"
<ResultScreen>
name: "result"
on_enter: root.manager.get_screen("calculator").set_values()
day_distance_result: day_distance_result
daily_consumption_result: daily_consumption_result
gasoline_after_result: gasoline_after_result
BoxLayout:
orientation: 'vertical'
padding: 20
spacing: 10
BoxLayout:
Label
text: "Daily distance result"
Label:
text: "0"
id: day_distance_result
BoxLayout:
Label
text: "Daily consumption result"
Label:
text: "0"
id: daily_consumption_result
BoxLayout:
Label
text: "Gasoline after"
Label:
text: "0"
id: gasoline_after_result
BoxLayout:
orientation: 'horizontal'
spacing: 10
Button:
text: 'Exit'
Button:
text: 'Recalculate'
on_release: root.manager.current = "calculator"
Upvotes: 1
Views: 49
Reputation: 39152
Since your set_values()
method is referencing attributes of the CalculateScreen
instance (like self.day_distance
, self.daily_consumption
, etc), you must provide those attributes. You can do this by modifying your counting()
method to set those attributes:
def counting(self, start_distance, finish_distance, start_gasoline, added_fuel, normal_consumption):
if self.added_fuel == 0:
self.day_distance = str(finish_distance - start_distance)
self.daily_consumption = str((int(self.day_distance) * normal_consumption) / 100)
self.gasoline_left = str(start_gasoline - float(self.daily_consumption))
else:
self.day_distance = str(finish_distance - start_distance)
self.daily_consumption = str((float(self.day_distance) * normal_consumption) / 100)
self.gasoline_left = str((start_gasoline + added_fuel) - float(self.daily_consumption))
# return self.day_distance, self.daily_consumption, self.gasoline_left
Note that since the return value is unused, that line can be eliminated.
And your calculations()
method does not call the counting()
method unless there is an exception. Probably just a typo. The call to counting()
should be unindented:
def calculations(self):
try:
start_distance = float(self.start_distance.text)
finish_distance = float(self.finish_distance.text)
start_gasoline = float(self.start_gasoline.text)
added_fuel = float(self.added_fuel.text)
normal_consumption = float(self.normal_consumption.text)
except:
start_distance = 0
finish_distance = 0
start_gasoline = 0
added_fuel = 0
normal_consumption = 0
self.counting(start_distance, finish_distance, start_gasoline, added_fuel, normal_consumption)
One other issue is the on_press
attributes of the Calculate
Button in your kv
file. Exactly the opposite of what anyone would expect, the construction:
Button:
text:'Calculate'
on_press: root.calculations()
on_press: root.set_values()
on_release: root.manager.current = "result"
results in root.set_values()
called first, and then root.calculations()
called second. A fix is to use just one on_press
attribute:
text:'Calculate'
on_press:
root.calculations()
root.set_values()
on_release: root.manager.current = "result"
Upvotes: 1