Reputation: 53
I'm attempting to create a stopwatch in Kivy. I've completed a skeleton on Sublime Text 3 (as shown in the code below). When I run the code on Sublime Text, a window opens, but Python crashes in 4.1s.
Here is the code in question:
import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.clock import Clock
from kivy.properties import NumericProperty
from kivy.lang import Builder
import time
class CrudeTimerGrid(GridLayout):
# Initialise timer with input start time
def __init__(self,start_time):
time = NumericProperty(start_time)
def tick(self):
if self.time > 0:
self.time -= 1
else:
pass
def start(self):
Clock.schedule_interval(self.tick,1)
def pause(self):
Clock.unschedule()
# incomplete code
def reset(self):
pass
class CrudeTimerApp(App):
def build(self):
# Testing timer by initialising timer with 20 seconds
return CrudeTimerGrid(20)
Builder.load_string('''
<CrudeTimerGrid>
id: timer
rows: 2
# insert formatting here
BoxLayout:
Label:
text: timer.time
BoxLayout:
Button:
text: "Start"
on_press: timer.start()
Button:
text: "Pause"
on_press: timer.pause()
Button:
text: "Reset"
on_press: timer.reset()
''')
CrudeTimerApp().run()
Newbie at StackOverflow too, so please let me know if any other info is needed. Thanks for your help!
Upvotes: 3
Views: 1150
Reputation: 39546
Main problem is here:
def __init__(self,start_time):
time = NumericProperty(start_time)
You should define Kivy properties at class level, please read this. Code'll stop crash if you change it like this:
class CrudeTimerGrid(GridLayout):
time = NumericProperty(0)
There're also few other changes you should do to make it finally work, here's full code version:
import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.clock import Clock
from kivy.properties import NumericProperty
from kivy.lang import Builder
import time
class CrudeTimerGrid(GridLayout):
time = NumericProperty(0)
def tick(self, *_):
if self.time > 0:
self.time -= 1
else:
pass
def start(self, *_):
self.cb = Clock.schedule_interval(self.tick,1)
def pause(self):
Clock.unschedule(self.cb)
# incomplete code
def reset(self, *_):
pass
class CrudeTimerApp(App):
def build(self):
# Testing timer by initialising timer with 20 seconds
return CrudeTimerGrid(time=20)
Builder.load_string('''
<CrudeTimerGrid>
id: timer
rows: 2
# insert formatting here
BoxLayout:
Label:
text: str(timer.time)
BoxLayout:
Button:
text: "Start"
on_press: timer.start()
Button:
text: "Pause"
on_press: timer.pause()
Button:
text: "Reset"
on_press: timer.reset()
''')
CrudeTimerApp().run()
Upd:
Any idea why 2 arguments are input into tick in the first place?
tick
passed to Clock.schedule_interval
to be called. This function schedules it's callback with additional parameter (as many other functions in Kivy also do). You can read a bit more about it in documentation.
You defined self.cb in order to reference it in Clock.unschedule, correct?
You can schedule many different functions with different intervals calling Clock.schedule_interval
multiple times. But how can Clock.unschedule
know which concrete of them to unschedule? In order to make Clock.unschedule
know what to unschedule you should pass to it value returned by Clock.schedule_interval
. Here's documentation section where this mechanism described.
Upvotes: 2