Time in Kivy

126 views
Skip to first unread message

Pascal Muller

unread,
Jul 10, 2017, 5:13:34 PM7/10/17
to kivy-...@googlegroups.com
Hello,
I need help to manage time in my kivy-python code.
For example, I don't know how to make a very simple application : the pyhon code increments a variable from 0 to 9 (0, 2, 3...9) and each time waits one second and only then change a label text with the value of the variable.
When I code that with time.sleep(1) I only see the last value : 9
I have the same problem if I want to draw lines : I only see all the lines at the end.
Thank you for your help.


Here is my code



from kivy.base import runTouchApp

from kivy.lang import Builder


from kivy.uix.floatlayout import FloatLayout

from kivy.graphics.vertex_instructions import (Rectangle,Ellipse,Line)

from kivy.graphics import Color

import time


Builder.load_string('''

<FloatLayout>:

Button:

text: "Exécute"

on_press: root.execute()

Label:

id: label_name

size_hint_y: 0.5

text: "Text"

''')


class FloatLayout(FloatLayout):

def execute(self):

mylabel = self.ids.label_name

for i in range(10):

print i

time.sleep(1)

mylabel.text=str(i)

with self.canvas:

Color(0, 1, 0, 1)

Line(points=[0,0,100+10*i,200])

runTouchApp(FloatLayout())



Monty Mole

unread,
Jul 10, 2017, 6:39:01 PM7/10/17
to kivy-...@googlegroups.com
Hi Pascal,
please include the indentations next time so the code will run properly and is readable.

You must avoid to spend too much time in a subroutine so kivy can update the layout.
Instead you have to register a call to a subroutine with clock.interval which is then called
automatically at given periods of time. To unregister it you have to return False. More on this here:
https://kivy.org/docs/api-kivy.clock.html

This way you can alter graphics or text, do running sliders etc.


#---------------------------------------------------------------------------------------




from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics.vertex_instructions import (Rectangle,Ellipse,Line)
from kivy.graphics import Color
from kivy.clock import Clock


import time

Builder.load_string('''

<FloatLayout>:
    Button:
        text: "Exécute"
        on_press: root.execute(self)

   
    Label:
        id: label_name
        size_hint_y: 0.5
        text: "Text"
''')


class FloatLayout(FloatLayout):
    counter = 10
   
    def print_to_label(self,*args):
        self.ids.label_name.text = str(self.counter ) 

        if self.counter == 0:
            self.ids.label_name.text = 'finished'
            return False         # unschedule
        else:
            self.counter -= 1

    def execute(self,btn):
        self.counter = 10   #reset counter
        Clock.schedule_interval(self.print_to_label, 1.)
       

runTouchApp(FloatLayout())



Pascal Muller

unread,
Jul 11, 2017, 3:45:26 PM7/11/17
to Kivy users support
Hi Monty Mole
It's exactly what I was looking for.
Thank you for you help and excuse me for the indentation, I'll be careful next time.
Pascal.

Monty Mole

unread,
Jul 12, 2017, 9:37:42 AM7/12/17
to Kivy users support
de nada

Pascal Muller

unread,
Aug 11, 2017, 9:45:35 AM8/11/17
to Kivy users support
Hello,
I'm trying to use Monty Mole's advices in another project : the Hanoi towers.
I would like to display each move and each state in a label and wait a delay before displaying next ones.
But once again, only last one is displayed.
Conversely, it works well with print function.
Here is my code.

Thank you for your help.
Pascal.



from kivy.base import runTouchApp

from kivy.lang import Builder

from kivy.uix.floatlayout import FloatLayout

from kivy.graphics.vertex_instructions import (Rectangle,Ellipse,Line)

from kivy.graphics import Color

from kivy.clock import Clock

import math

import time

from kivy.clock import Clock


Builder.load_string('''

<FloatLayout>:

    BoxLayout:

        orientation: 'vertical'

        Label:

            text:"Hanoi towers"

            size_hint_y: 0.2

        BoxLayout:

            size_hint_y: 0.3

            Label:

                size_hint_x: 0.5

            Label:

                size_hint_x: 0.3

                text:"LEGO NXT : "

            CheckBox:

                size_hint_x: 0.2

                id: checkbox_name

            Label:

                size_hint_x: 0.5

        BoxLayout:

            size_hint_y: 0.3

            Label:

                size_hint_x: 0.5

                text:"Number of rings : "

            Label:

                size_hint_x: 0.1

                text: str(int(slider_name.value))

            Slider:

                id: slider_name

                size_hint_x: 2

                step: 1

                min:1

                max:9

                value: 2

        BoxLayout:

            size_hint_y: 0.3

            Label:

                size_hint_x: 0.5

                text:"Delay : "

            Label:

                size_hint_x: 0.1

                text: str(int(slider2_name.value))

            Slider:

                id: slider2_name

                size_hint_x: 2

                step: 1

                min:0

                max:9

                value: 1

        Label:

            size_hint_y: 0.4

            text: 'Time estimation : ' + str(int((2**slider_name.value-1)*slider2_name.value)) + ' second(s)'

        Button:

            size_hint_y: 0.5

            text: "Execute"

            on_press: root.execute(self)

        Label:

            id: label_action__name

            size_hint_y: 0.5

            text: "Action : "

        Label:

            id: label_result__name

            size_hint_y: 0.5

            text: "Rings position : "

        Label:

            size_hint_y: 3  

''')    



class FloatLayout(FloatLayout):

    m1=[]

    m2=[]

    m3=[]

    text_action=''

    end = 0

    def hanoi(self,n,s,d,t):

        if n>0:

            self.hanoi(n-1,s,t,d)

            if s==1:

                self.m1.remove(n)

            if d==1:

                self.m1.append(n)

            if s==2:

                self.m2.remove(n)

            if d==2:

                self.m2.append(n)

            if s==3:

                self.m3.remove(n)

            if d==3:

                self.m3.append(n)

            self.m1.sort()

            self.m2.sort()

            self.m3.sort()

            self.text_action='Move ring ' + str(n) + ' from ' + str(s) + ' to '+ str(d)

            print self.text_action,self.m1,self.m2,self.m3

            time.sleep(1)

            self.hanoi(n-1,t,d,s)

           


    def update(self,*args):

        self.ids.label_result__name.text='Rings position : ' + str(self.m1)+' '+str(self.m2)+' '+str(self.m3)

        self.ids.label_action__name.text=self.text_action

        if self.end == 1:

            return False         # unschedule


           

    def execute(self,btn):

        delai = self.ids.slider2_name

        Clock.schedule_interval(self.update,delai.value)

        level = self.ids.slider_name

        self.m1=range(1,int(level.value)+1)

        self.m2=[]

        self.m3=[]

        self.hanoi(int(level.value),1,3,2)

        end = 1

        print 'End'

 

runTouchApp(FloatLayout())  




ZenCODE

unread,
Aug 11, 2017, 4:54:57 PM8/11/17
to Kivy users support
Like so?

#time.sleep(1)

from kivy.clock import Clock
Clock.schedule_once(lambda dt: self.hanoi(n - 1, t, d, s), 1)

Pascal Muller

unread,
Aug 17, 2017, 2:27:22 PM8/17/17
to Kivy users support
Hello
I tried to delete "time.sleep" and to use "clock.schedule once" but it doesn't work.
Here is my new code.
Thnak you for your help.
Pascal.

            #self.hanoi(n-1,s,t,d)


            Clock.schedule_once(lambda dt: self.hanoi(n-1,s,t,d), 5)


            if s==1:


                self.m1.remove(n)


            if d==1:


                self.m1.append(n)


            if s==2:


                self.m2.remove(n)


            if d==2:


                self.m2.append(n)


            if s==3:


                self.m3.remove(n)


            if d==3:


                self.m3.append(n)


            self.m1.sort()


            self.m2.sort()


            self.m3.sort()


            self.text_action='Move ring ' + str(n) + ' from ' + str(s) + ' to '+ str(d)


            print self.text_action,self.m1,self.m2,self.m3


  #         time.sleep(1)


            Clock.schedule_once(lambda dt: self.hanoi(n - 1, t, d, s), 5)


   #        self.hanoi(n-1,t,d,s)


           


    def update(self,*args):


        self.ids.label_result__name.text='Rings position : ' + str(self.m1)+' '+str(self.m2)+' '+str(self.m3)


        self.ids.label_action__name.text=self.text_action


        if self.end == 1:


            return False         # unschedule


           


    def execute(self,btn):


        delai = self.ids.slider2_name


        Clock.schedule_interval(self.update,0.1)


        level = self.ids.slider_name


        self.m1=range(1,int(level.value)+1)


        self.m2=[]


        self.m3=[]


        Clock.schedule_once(lambda dt: self.hanoi(int(level.value),1,3,2), 5)


     #  self.hanoi(int(level.value),1,3,2)


        end = 1


        print 'End'


 


runTouchApp(FloatLayout())


           




   


   



ZenCODE

unread,
Aug 17, 2017, 2:53:07 PM8/17/17
to kivy-...@googlegroups.com
Please can you define "it does not work". The labels update and seem to display the solution.  What exactly "does not work"?

p.s. It is a REALLY good idea not to replace the FloatLayout definition with your own. You should really give your FloatLayout it's own name, so as not to confuse your FloatLayout with the original Kivy FloatLayout....

Bill Janssen

unread,
Aug 18, 2017, 8:09:51 PM8/18/17
to Kivy users support
You probably shouldn't call your class "FloatLayout", for one thing.  But what is it that you think will call your "execute" method?  That's never getting called, that I can see.

Bill

Pascal Muller

unread,
Sep 3, 2017, 1:33:38 PM9/3/17
to Kivy users support
Hello,
Thank you for being interested in my project.
And excuse me for not having posted before : I wasn't home last weeks.

First of all I changed the name of my class. Thank you for this advice.

Then I tried to use clock.schedule_once in lines from 94 to 101 in the hanoi function
I explain : moving number rings from start position to end position using the third position (temp) as a help is equivalent to three moves :
- move number-1 rings from start to temp
- move one ring from start to end
- move number-1 rings from temp to end
It's recursion
The function does something other than calling itself only when n=1 : it then prints move and result and change label texts so that the user can see what is done in the gaphical interface.
My original problem is that I didn't succed in updating these labels : they only update at the end.
And I don't see how using clock.schedule_once would solve it.
When I use it, nothing happens during a while and and all moves are printed at once and in the label I only see last position.

Thank you for your help.
Here is my last code attempt


from kivy.base import runTouchApp


from kivy.lang import Builder




from kivy.uix.floatlayout import FloatLayout


from kivy.graphics.vertex_instructions import (Rectangle,Ellipse,Line)


from kivy.graphics import Color


from kivy.clock import Clock


import math


import time


from kivy.clock import Clock








Builder.load_string('''


<Hanoi_Class>:

class Hanoi_Class(FloatLayout):


   


    text_action=''


    end = 0                    


    def hanoi(self,number,start,end,temp):


        if number==1:


            self.text_action="Move ring "+str(rings[start-1][0])+" altitude "+str(len(rings[start-1]))+" from position "+str(start)+" to position "+str(end)


            print (self.text_action)


            rings[end-1].insert(0,rings[start-1][0])


            del(rings[start-1][0])


            print("Result : "+str(rings)+"\n")


        else:


            Clock.schedule_once(lambda dt: self.hanoi(number-1,start,temp,end),delay.value)






            Clock.schedule_once(lambda dt: self.hanoi(1,start,end,temp),delay.value)


            time.sleep(delay.value+1)


           


            Clock.schedule_once(lambda dt: self.hanoi(number-1,temp,end,start),delay.value)






         


           


    def update(self,*args):


        self.ids.label_result__name.text='Rings position : ' + str(rings)


        self.ids.label_action__name.text=self.text_action


        if self.end == 1:


            return False         # unschedule


           


    def execute(self,btn):


        global rings


        global delay


        delay = self.ids.slider2_name


        Clock.schedule_interval(self.update,0.1)


        level = self.ids.slider_name


        rings=[list(range(1,level.value+1)),[],[]]


        self.hanoi(int(level.value),1,3,2)


        end = 1


        print ('End')


 


runTouchApp(Hanoi_Class())


           




   


   



Reply all
Reply to author
Forward
0 new messages