G.N.
G.N.

Reputation: 139

Scheduling operations with Kivy

I'm trying to postpone an event using Kivy. More specifically, I want to present a text label on screen, and then delete it after N seconds. So far I understand that time.sleep won't do the job. Instead, I try to create a separate function (called eraser()) that deletes whatever is on the screen, then to call it using Clock.schedule_once(eraser, n).

This is what I have so far:

class myLayout(FloatLayout):
    def eraser(self):
        self.canvas.clear()

    def _keyboard_on_key_down(self, keyboard, keycode, text, modifiers):
        self.canvas.clear()

        global i
        i = i + 1
        initialy = 400-(stim_list[i]/2)
        xlab = Label(text='X', pos=(0, 350))

        with self.canvas:
            self.add_widget(xlab)
            Color(1., 1, 1)
            Rectangle(pos=(initialx, initialy), size=(stimwidth, stim_list[i]))

        Clock.schedule_once(eraser(),3)

That's not really working, I would appreciate if anyone can think of the right/better way to do so.

Upvotes: 0

Views: 348

Answers (1)

Peter Badida
Peter Badida

Reputation: 12189

Widget and Canvas are completely different things, therefore cleaning only the canvas obviously won't remove the widget itself and in the end with this technique the FloatLayout will have a lot of Label widgets as children without actually removing them - call it a leak if you want :)

Widget uses add_widget(), remove_widget() and clear_widgets() calls and each of them is out of the with <canvas> block, though yes, it works even that way if you actually need it to behave like that.

Clock.schedule_once() call on the other hand uses the function/method you pass to it, which in your case is just a returning value of eraser() (which is None) and executes the function at the same place where you wrote it with the brackets (eraser() → call, eraser → just a function).

Therefore:

  • use add_widget(), remove_widget() and clear_widgets()
    • don't place them into with <canvas> block unless necessary (mostly isn't!)
  • pass the function/method as an argument, not their returned values (don't use brackets)

Example:

from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.base import runTouchApp
from kivy.uix.floatlayout import FloatLayout

Builder.load_string('''
<Test>:
    Button:
        size_hint: None, None
        on_release: root.test()
''')


class Test(FloatLayout):
    def eraser(self, *args):
        self.clear_widgets()

    def test(self, *args):
        lab = Label(text='Hello world!')
        self.add_widget(lab)
        Clock.schedule_once(self.eraser, 3)


runTouchApp(Test())

Upvotes: 1

Related Questions