I’m just now learning Kivy for some UI options when creating stuff with Python. The thing I’m strugling right now are loops and how to make them work with Kivy.
Example below is a very straightforward loop that should print each number to a Kivy label (replacing previous).
Currently when pressing the button I only get the last digit on screen because the entire function runs completely – which makes sense. But my question is how can I setup the button so that when I press it, it runs only one iteration of the loop.
My .py file:
from kivy.app import App from kivy.core.window import Window from kivy.lang import Builder from kivy.uix.widget import Widget Window.size=(300,300) Builder.load_file('loop.kv') class MyLayout(Widget): def loop(self): for i in range(10): self.ids.label_print.text = str(i) pass class LoopApp(App): def build(self): return MyLayout() if __name__=='__main__': LoopApp().run()
My .kv file:
<MyLayout> BoxLayout: orientation: 'vertical' size: root.height, root.width Label: id: label_print font_size: 32 Button: text: 'Loop' on_press: root.loop()
Currently it only shows 9 as a result and I would expect to go from 0 and add 1 for each button press:
Basically your loop works correctly, but happens immediately so you only see the 9 and not a sequence or anything. What you can do is to use
kivy.clock to schedule an interval to a callback function, specify the interval time and stop the schedule at a certain point. If you would skip the kivy.clock part, your GUI is frozen until the function is finished. Example:
from kivy.app import App from kivy.core.window import Window from kivy.lang import Builder from kivy.uix.widget import Widget from kivy.clock import Clock from timeit import time Window.size=(300,300) Builder.load_file('loop.kv') class MyLayout(Widget): loop_thread = None def callback_to_loop(self, dt): # dt is the interval-time # this is required because initially the text is an empty string try: current = int(self.ids.label_print.text) except: current = 0 # simply add up the numbers self.ids.label_print.text = str(current+1) # stop at a certain point and unschedule the thread if current == 11: Clock.unschedule(self.loop_thread) def loop(self): # schedule the thread with an interval-time = 1 self.loop_thread = Clock.schedule_interval(self.callback_to_loop, 1) pass class LoopApp(App): def build(self): return MyLayout() if __name__=='__main__': LoopApp().run()