Clock.schedule_once() problem

70 views
Skip to first unread message

Dan Moormann

unread,
Apr 11, 2024, 11:28:47 PM4/11/24
to Kivy users support
I'm trying to create a small delay so that I can see the progress of a simple app that changes the color of a 4x4 set of buttons to create a crude spiral.
The order of "lighting" is specified in self.x16.
The output indicates that it is running through all 16 buttons then running the Clock.schedule() 16 times.  

How do I get it to actually call click_it() for each button and delay until the next call?

Please note: None of the options under Flash (spinner) are working except Spiral (sorta).
main.py
grid.kv
linenum.py

elli...@cox.net

unread,
Apr 12, 2024, 11:36:36 AM4/12/24
to Kivy users support
You have 2 issues in the code, both are similar.
You have a for loop that will run to completion:

if self.flash_choice=='Spiral':
   
self.x16 = [0, 1, 2, 3, 7, 11, 15, 14, 13, 12, 8, 4, 5, 6, 10, 9]

   
for i in range(len(self.x16)):
       
self.current = self.x16[i]
       
print('clocking',i,self.current)
       Clock.schedule_once(
self.click_it, self.dt)
After the loop has completed, the last value in self.x16 will be in self.current.  You will have scheduled self,.click_it to run 16 times, all on the next frame, and when the run you will have that last value of self.current.

Here are 2 ways to solve the problem.   You could create an iterator (see the python builtins iter/next)  and schedule a delay on each iteration; or you could change click_it in and pass in a parameter and increases the delay time each time you move though the loop.

When you use clock.schedule_once(), you are scheduling a callback at some time in the future.  if you are going to schedule a set of delays in a loop you would want to increase the delay time for each iteration so then don't all fire at the same time.

Hope that made sense.





From: kivy-...@googlegroups.com <kivy-...@googlegroups.com> on behalf of Dan Moormann <dan...@gmail.com>
Sent: Thursday, April 11, 2024 8:28 PM
To: Kivy users support <kivy-...@googlegroups.com>
Subject: [kivy-users] Clock.schedule_once() problem
 
--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/7da9eeda-9bd4-435a-8993-4de9eb11dde4n%40googlegroups.com.

elli...@cox.net

unread,
Apr 12, 2024, 11:45:35 AM4/12/24
to Kivy users support
Here is a fix:

def flash_it(self):
   
#println('def flash')
   
self.box_it()   #clear it back to grey
   #self.random=False
   
self.flash_choice=self.root.ids.flash.text
   
self.current=0
   
self.next = 1
   
self.column=0
   
self.direction=1
   
#xhold=self.current_color
   
self.dt=0  #delay time seconds
   
self.range=int(self.root.ids.spin.text)

   
if self.flash_choice=='Spiral':
       
self.x16 = [0, 1, 2, 3, 7, 11, 15, 14, 13, 12, 8, 4, 5, 6, 10, 9]
       delay =
0
       
for button in self.x16:
           p = partial(
self.click_it, button)
           Clock.schedule_once(p, delay)
           delay +=
0.5

def click_it(self, button, dt):
   
print(f'clickit {button} {dt}')
   xcolor =
self.current_color
   
if self.random:
       xcolor = get_random_color()
   
self.button_list[button].background_color = xcolor
you can import get_random_color from kivy.utils.

From: kivy-...@googlegroups.com <kivy-...@googlegroups.com> on behalf of elli...@cox.net <elli...@cox.net>
Sent: Friday, April 12, 2024 8:36 AM

To: Kivy users support <kivy-...@googlegroups.com>
Subject: Re: [kivy-users] Clock.schedule_once() problem
 

Dan Moormann

unread,
Apr 12, 2024, 4:17:17 PM4/12/24
to Kivy users support
Eliott - your solution worked.  Thank you.  

I never really understood how Clock.schedule_once() worked until now.  If I'm wrong, let me know.
The loop that calls Clock.scedule_once() runs completely through as it happens quicker than the delay.
Then after the first delay click_it runs.  Then each call to click_it runs at an additional delay afterward.

I'll try to explore iter/next and see if I like it better.

Elliot Garbus

unread,
Apr 12, 2024, 5:04:56 PM4/12/24
to kivy-...@googlegroups.com
Yes you’re correct, but let me add a little additional info. When you call Clock.schedule_once(), you are putting the callback and the delay value on a list, then the call returns. 

In the kivy event loop, that list of callbacks and delays is scanned each frame. If the delay time has been met, the callback is called. 

In short you are scheduling a callback to be run in the future.

Sent from my iPhone

On Apr 12, 2024, at 1:17 PM, Dan Moormann <dan...@gmail.com> wrote:

Eliott - your solution worked.  Thank you.  
Reply all
Reply to author
Forward
0 new messages