Animated Clock in kivy

67 views
Skip to first unread message

Prabhat K.C.

unread,
Mar 4, 2020, 9:53:15 PM3/4/20
to Kivy users support
I need to include a clock in one of my screens. I found some help online on how to do a 360 degree clock but I am being unable to integrate within my screenmanager in one of the screens. I am getting "Ticks" class not found error. What would be the easiest approach to fix this? Below are my python and kivy files.

main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty, NumericProperty
from kivy.uix.image import Image
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.actionbar import ActionButton
from kivy.uix.screenmanager import FadeTransition, FallOutTransition
from kivy.graphics import Color, Rectangle, Line
from kivy.uix.widget import Widget
from kivy.uix.slider import Slider
from math import cos, sin, pi
from kivy.clock import Clock
import datetime


class HomeWin(Screen):
pass
class InchFootWin(Screen):
pass
class FootYardWin(Screen):
pass
class DayHourWin(Screen):
pass
class WeekDayWin(Screen):
pass
class ResultWindow(Screen):
pass

class LengthWin(Screen):
pass

class TimeWin(Screen):
pass

class LoginWin(Screen):
pass

class InterFootInch(Screen):
# def manipulate(self, slider):
# app = App.get_running_app()
# self.canvas.rect1.size = int(slider.value)
# self.rect2.size = int(slider.value) * 7
pass

class InterFootYard(Screen):
pass

class InterDayHour(Screen):
pass


class scrManager(ScreenManager):
def FeetToYard(self, userFootYard):
app = App.get_running_app()
if (float(userFootYard.text)/3) > 1:
app.result = f'{float(userFootYard.text)/3:0.2f}' + " Yards"
else:
app.result = f'{float(userFootYard.text)/3: 0.2f}' + " Yard"

def YardToFeet(self, userFootYard):
app = App.get_running_app()
if (3 * float(userFootYard.text)) > 1:
app.result = f'{(3 * float(userFootYard.text)):0.2f}' + " Feet"
else:
app.result = f'{(3 * float(userFootYard.text)):0.2f}' + " Foot"

def FeetToInches(self, userInchFoot):

app = App.get_running_app()
if (12 * float(userInchFoot.text)) > 1:
app.result = f'{(12 * float(userInchFoot.text)):0.2f}' + " Inches"
else:
app.result = f'{(12 * float(userInchFoot.text)):0.2f}' + " Inch"


def InchToFeet(self, userInchFoot):
#inchData = userSource.text
#tempData2 = str(int(inchData) / 12)
app = App.get_running_app()
if (float(userInchFoot.text)/12) > 1:
app.result = f'{float(userInchFoot.text)/12:0.2f}' + " Feet"
else:
app.result = f'{float(userInchFoot.text) / 12:0.2f}' + " Foot"

def DayToHour(self, userDayHour):
app = App.get_running_app()
if(24 * float(userDayHour.text)) > 1:
app.result = f'{(24 * float(userDayHour.text)):0.2f}' + " Hours"
else:
app.result = f'{(24 * float(userDayHour.text)):0.2f}' + " Hour"

def HourToDay(self, userDayHour):
app = App.get_running_app()
if(float(userDayHour.text)/24) > 1:
app.result = f'{float(userDayHour.text)/24:0.2f}' + " Days"
else:
app.result = f'{float(userDayHour.text)/24:0.2f}' + " Day"

def WeekToDay(self, userWeekDay):
app = App.get_running_app()
if(7 * float(userWeekDay.text)) > 1:
app.result = f'{(7 * float(userWeekDay.text)):0.2f}' + " Days"
else:
app.result = f'{(7 * float(userWeekDay.text)):0.2f}' + " Day"

def DayToWeek(self, userWeekDay):
app = App.get_running_app()
if(float(userWeekDay.text)/7) > 1:
app.result = f'{float(userWeekDay.text)/7:0.2f}' + " Weeks"
else:
app.result = f'{float(userWeekDay.text)/7:0.2f}' + " Week"



kv = Builder.load_file("clockunit.kv")

class Ticks(Widget):
def __init__(self, **kwargs):
super(Ticks, self).__init__(**kwargs)
self.bind(pos=self.update_clock)
self.bind(size=self.update_clock)

def update_clock(self, *args):
self.canvas.clear()
with self.canvas:
time = datetime.datetime.now()
Color(0.2, 0.5, 0.2)
Line(points=[self.center_x, self.center_y, self.center_x+0.8*self.r*sin(pi/30*time.second), self.center_y+0.8*self.r*cos(pi/30*time.second)], width=1, cap="round")
Color(0.3, 0.6, 0.3)
Line(points=[self.center_x, self.center_y, self.center_x+0.7*self.r*sin(pi/30*time.minute), self.center_y+0.7*self.r*cos(pi/30*time.minute)], width=2, cap="round")
Color(0.4, 0.7, 0.4)
th = time.hour*60 + time.minute
Line(points=[self.center_x, self.center_y, self.center_x+0.5*self.r*sin(pi/360*th), self.center_y+0.5*self.r*cos(pi/360*th)], width=3, cap="round")

class MyTouch(Widget):
pass



class MyMainApp(App):
result = StringProperty("initialization")
#rect1.size = ObjectProperty(0,50)
# rect2.size = ObjectProperty(0,50)
def build(self):
return kv




if __name__ == "__main__":
MyMainApp().run()

clockunit.kv
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
#:import FadeTransition kivy.uix.screenmanager.FallOutTransition
#:import math math

scrManager:
id: scman
LoginWin:
name: "loginWin"
HomeWin:
name: "homeWin"
LengthWin:
name: "lengthWin"
TimeWin:
name: "timeWin"
InchFootWin:
name: "inchFootWin"
FootYardWin:
name: "footYardWin"
ResultWindow:
name: "result"
DayHourWin:
name: "dayHourWin"
WeekDayWin:
name: "weekDayWin"
InterFootInch:
name: "interFootInchWin"
InterFootYard:
name: "interFootYardWin"
InterDayHour:
name: "interDayHourWin"

<HomeButton@ButtonBehavior+Image>
source: 'home.jpg'
size_hint: 0.25,0.1
on_release:
app.root.current = "homeWin"
pos_hint: {"x": 0.35}
<LeftDownBtn@Button>
size_hint: 0.17, 0.12
pos_hint: {"x": 0.15 , "top": 0.3}
opacity: 0.8
<RightDownBtn@Button>
size_hint: 0.17, 0.12
pos_hint: {"x": 0.65, "top": 0.3}
opacity: 0.8
[ClockNumber@Label]:
text: str(ctx.i)
pos_hint: {"center_x": 0.5+0.42*math.sin(math.pi/6*(ctx.i-12)), "center_y": 0.5+0.42*math.cos(math.pi/6*(ctx.i-12))}
font_size: self.height/16


<LoginWin>:
FloatLayout:
Image:
source: 'locked.jpg'
pos_hint: {"x":0, "top":1}
size_hint: 1, 1
allow_stretch: True
keep_ratio: False
LeftDownBtn:
text: 'I AM A TEACHER'
on_release:
root.manager.transition = FadeTransition()
app.root.current = "homeWin"
RightDownBtn:
text: 'I AM A STUDENT'
on_release:
root.manager.transition = FadeTransition()
app.root.current = "homeWin"


<HomeWin>:
FloatLayout:
Image:
source: 'bgnd.jpg'
pos_hint: {"x":0, "top":1}
size_hint: 1, 0.3
allow_stretch: True
keep_ratio: False
Image:
source: 'metric.jpg'
pos_hint: {"x":0, "top":0.7}
size_hint: 1,0.7
allow_stretch: True
keep_ratio: False

FloatLayout:
cols: 1
Label:
text: "Select a category of conversion"
color: 0,0.6,1,0.9
font_size: 32
size_hint: 1,0.3
pos_hint: {"x":0, "top":1}
FloatLayout:
cols: 2
Button:
id: lengthBtn
text: "LENGTH"
font_size: 30
color: 0,0.9,0.9,1
on_release:
root.manager.transition = FadeTransition()
app.root.current = "lengthWin"
size_hint: 0.23,0.1
pos_hint: {"x":0.1, "top":0.3}
opacity: 0.8
Button:
id: timeBtn
text: "TIME"
font_size: 30
color: 0,0.9,0.9,1
on_release:
root.manager.transition = FadeTransition()
app.root.current = "timeWin"

size_hint: 0.23,0.1
pos_hint: {"x":0.6, "top":0.3}
opacity: 0.8
HomeButton:



<TimeWin>:
FloatLayout:
Image:
source: 'time.jpg'
pos_hint: {"x":0, "top":1}
size_hint: 1, 1
allow_stretch: True
keep_ratio: False
Label:
text: "SELECT"
color: 0.9,0.4,0.7,1
pos_hint: {"x": 0, "top": 0.9}
font_size: 40
size_hint: 1,0.4

FloatLayout:

LeftDownBtn:
id: weekToDayBtn
text: "Week <--> Day"
on_release:
root.manager.transition = FadeTransition()
app.root.current = "weekDayWin"

RightDownBtn:
id: hourToMinBtn
text: "Hour <--> Day"
on_release:
root.manager.transition = FadeTransition()
app.root.current = "dayHourWin"


HomeButton:


<LengthWin>:
FloatLayout:
Image:
source: 'measure.jpg'
Label:
text: "Choose your desired conversion"
color: 0.9,0.4,0.7,1
pos_hint: {"x": 0, "top": 0.9}
font_size: 40
size_hint: 1,0.4

FloatLayout:
LeftDownBtn:
id: inchToFootBtn
text: "Inch <--> Feet"
on_release:
root.manager.transition = FadeTransition()
app.root.current = "inchFootWin"
color: 0.9,0.8,0.8,1

RightDownBtn:
id: FeetToYard
text: "Feet <--> Yard"
on_release:
root.manager.transition = FadeTransition()
app.root.current = "footYardWin"
color: 0.9,0.8,0.8,1

HomeButton:

<FootYardWin>:
FloatLayout:
Image:
source: 'footyard.jpg'
pos_hint: {"x":0, "top":1}
size_hint: 1, 1
allow_stretch: True
keep_ratio: False

FloatLayout:

Label:
text: "Input the number"
color: 0.1,0.5,0.4,1
pos_hint: {"x": 0.15, "top": 0.9}
font_size: 40
size_hint: 0.4,0.4
TextInput:
id: userFootYard
multiline: False
color: 0.6,0.4,0.7,1
pos_hint: {"x": 0.6, "top": 0.75}
font_size: 40
size_hint: 0.17,0.1
multiline: False
LeftDownBtn:
id: footToYardBtn
text: "Foot => Yard"
on_press:
app.root.FeetToYard(userFootYard)
on_release:
root.manager.transition = FadeTransition()
app.root.current = "result"

RightDownBtn:
id: yardToFootBtn
text: "Yard => Foot"
on_press:
app.root.YardToFeet(userFootYard)
on_release:
root.manager.transition = FadeTransition()
app.root.current = "result"

Button:
text: "Try Interactive"
on_release:
app.root.current = "interFootYardWin"
size_hint: 0.2, 0.11
pos_hint: {"x": 0.39 , "top": 0.46}
opacity: 0.8

HomeButton:

<InchFootWin>:
FloatLayout:
Image:
source: 'footyard.jpg'
pos_hint: {"x":0, "top":1}
size_hint: 1, 1
allow_stretch: True
keep_ratio: False

FloatLayout:

Label:
text: "Input the number"
color: 0.1,0.5,0.4,1
pos_hint: {"x": 0.15, "top": 0.9}
font_size: 40
size_hint: 0.4,0.4
TextInput:
id: userInchFoot
multiline: False
color: 0.6,0.4,0.7,1
pos_hint: {"x": 0.6, "top": 0.75}
font_size: 40
size_hint: 0.17,0.1
multiline: False
LeftDownBtn:
id: FootToInchBtn
text: "Foot => Inch"
on_press:
app.root.FeetToInches(userInchFoot)
on_release:
root.manager.transition = FadeTransition()
app.root.current = "result"

RightDownBtn:
id: inchToFootBtn
text: "Inch => Foot"
on_press:
app.root.YardToFeet(userInchFoot)
on_release:
root.manager.transition = FadeTransition()
app.root.current = "result"

Button:
text: "Try Interactive"
on_release:
app.root.current = "interLenWin"
size_hint: 0.2, 0.11
pos_hint: {"x": 0.39 , "top": 0.46}
opacity: 0.8

HomeButton:

<DayHourWin>:
FloatLayout:
Image:
source: 'time.jpg'
pos_hint: {"x":0, "top":1}
size_hint: 1, 1
allow_stretch: True
keep_ratio: False

FloatLayout:

Label:
text: "Input the number"
color: 0.3,0.4,0.9,1
pos_hint: {"x": 0.15, "top": 0.9}
font_size: 40
size_hint: 0.4,0.4
TextInput:
id: userDayHour
color: 0.6,0.4,0.7,1
pos_hint: {"x": 0.6, "top": 0.75}
font_size: 40
size_hint: 0.17,0.1
multiline: False
LeftDownBtn:
id: dayToHourBtn
text: "Convert Day To Hour"
on_press:
app.root.DayToHour(userDayHour)
on_release:
root.manager.transition = FadeTransition()
app.root.current = "result"

RightDownBtn:
id: hourToDayBtn
text: "Convert Hour to Day"
on_press:
app.root.HourToDay(userDayHour)
on_release:
root.manager.transition = FadeTransition()
app.root.current = "result"

Button:
text: "Try Interactive"
on_release:
app.root.current = "interDayHourWin"
size_hint: 0.2, 0.11
pos_hint: {"x": 0.39 , "top": 0.46}
opacity: 0.8


HomeButton:

<WeekDayWin>:
GridLayout:
cols: 2
Label:
text: "Input the number"
TextInput:
id: userWeekDay
multiline: False
Button:
id: weekToDayBtn
text: "Convert Week to Day"
on_press:
app.root.WeekToDay(userWeekDay)
on_release:
root.manager.transition = FadeTransition()
app.root.current = "result"

Button:
id: dayToWeekBtn
text: "Convert Day To Week"
on_press:
app.root.DayToWeek(userWeekDay)
on_release:
root.manager.transition = FadeTransition()
app.root.current = "result"

HomeButton:




<ResultWindow>:
on_enter:
answer.text = 'Your Result: ' + app.result
FloatLayout:
Image:
source: 'blank.jpg'
pos_hint: {"x":0, "top":1}
size_hint: 1, 1
allow_stretch: True
keep_ratio: False

FloatLayout:
Label:
id: answer
color: 0.2,0.4,0.7,1
pos_hint: {"x": 0, "top": 0.8}
font_size: 40
size_hint: 1,0.4


Button:
text: "BACK"
font_size: 30
color: 0,0.9,0.9,1
on_release:
app.root.current = "homeWin"
size_hint: 0.23,0.1
pos_hint: {"x":0.3, "top": 0.35}
opacity: 0.3

HomeButton:
#Comments
<InterFootInch@BoxLayout>:
orientation: 'vertical'
canvas:
Color:
rgba: .5, .5, .5, 1

Rectangle:
size: self.size
pos: self.pos
source: 'bckgndn.jpg'
Slider:
size_hint_y: .25

id: slider
min: 0
max: 50
step: 1
orientation: 'horizontal'
canvas:
Color:
rgba: 0,0.5,0.5,1
Rectangle:
size: (1 + self.value * 1, 50)
pos: (50 ,450)
Color:
rgba: 0.2,1,0.2,1
Rectangle:
size: (7 + self.value * 7, 50)
pos:(50,250)
#Label:
#text: str(slider.value)
# font_size: 40
Label:
text: str(slider.value) + ' Feet =' + str(7*slider.value) + ' Inches'
pos: (100,100)
font_size: 30
color: 0.2,0.6,0.6,1
HomeButton:

<InterFootYard@BoxLayout>:
orientation: 'vertical'
canvas:
Color:
rgba: .5, .5, .5, 1

Rectangle:
size: self.size
pos: self.pos
source: 'bckgndn.jpg'
Slider:
size_hint_y: .25

id: slider
min: 0
max: 50
step: 1
orientation: 'horizontal'
canvas:
Color:
rgba: 0,0.5,0.5,1
Rectangle:
size: (1 + self.value * 1, 50)
pos: (50 ,450)
Color:
rgba: 0.2,1,0.2,1
Rectangle:
size: (3 + self.value * 3, 50)
pos:(50,250)
#Label:
#text: str(slider.value)
# font_size: 40
Label:
text: str(slider.value) + ' Yard =' + str(3*slider.value) + ' Feet'
pos: (100,100)
font_size: 30
color: 0.2,0.6,0.6,1
HomeButton:

<InterDayHour>:

face: face
ticks: ticks
FloatLayout:
id: face
size_hint: None, None
pos_hint: {"center_x":0.5, "center_y":0.5}
size: 0.9*min(root.size), 0.9*min(root.size)
canvas:
Color:
rgb: 0.1, 0.1, 0.1
Ellipse:
size: self.size
pos: self.pos
ClockNumber:
i: 1
ClockNumber:
i: 2
ClockNumber:
i: 3
ClockNumber:
i: 4
ClockNumber:
i: 5
ClockNumber:
i: 6
ClockNumber:
i: 7
ClockNumber:
i: 8
ClockNumber:
i: 9
ClockNumber:
i: 10
ClockNumber:
i: 11
ClockNumber:
i: 12
Ticks:
id: ticks
r: min(root.size)*0.9/2
HomeButton:

Elliot Garbus

unread,
Mar 4, 2020, 11:18:58 PM3/4/20
to kivy-...@googlegroups.com

I have not come across that issue – but you do not have a Clock.schedule_interval().  I would expect to see this to drive the update of the second hand.

--
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/a8a9507f-da5e-4c0c-8942-07a0a0b46f13%40googlegroups.com.

 

Prabhat K.C.

unread,
Mar 4, 2020, 11:28:28 PM3/4/20
to Kivy users support
My primary issue here is that I cannot run the program and the error is " kivy.factory.FactoryException: Unknown class <Ticks>" 
I found this code as a stand alone code. so the ticks class in the python file and <InterDayHour> Screen in the kivy file is what I am trying to work with. I know I didn't put the Ticks class properly in the python file, and don't know what to do there. Also if I changed the positioning of Ticks class or definitions within them, I am not quite sure how to accordingly make changes in the kivy file. You have helped me so much in the past, so I am quite hopeful you could help me here. 

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-...@googlegroups.com.

Prabhat K.C.

unread,
Mar 4, 2020, 11:41:59 PM3/4/20
to Kivy users support
Or can you guide me how can make a clock that moves from a scratch so I can put it inside one of my blank screens. A very simple clock that moves would work to start with. Thank you.


On Wednesday, March 4, 2020 at 10:18:58 PM UTC-6, Elliot Garbus wrote:

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-...@googlegroups.com.

Elliot Garbus

unread,
Mar 4, 2020, 11:48:04 PM3/4/20
to kivy-...@googlegroups.com
What is the series of buttons you press to see this error?

Sent from my iPad

On Mar 4, 2020, at 9:28 PM, 'Prabhat K.C.' via Kivy users support <kivy-...@googlegroups.com> wrote:


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/8aa83180-e82c-4434-8f25-c852637e168f%40googlegroups.com.

Elliot Garbus

unread,
Mar 4, 2020, 11:49:09 PM3/4/20
to kivy-...@googlegroups.com
Does it need to be an analog clock face? Is a digital clock ok?

Sent from my iPad

On Mar 4, 2020, at 9:42 PM, 'Prabhat K.C.' via Kivy users support <kivy-...@googlegroups.com> wrote:


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/a470241e-7cf9-4582-b6e9-4a3191c87da8%40googlegroups.com.

Prabhat K.C.

unread,
Mar 4, 2020, 11:51:32 PM3/4/20
to Kivy users support
Needed an analog clock face with hour minute and second hands which in future I am planning to make interactive but that is for later. For now, just an analog clock that rotates.

Elliot Garbus

unread,
Mar 5, 2020, 8:05:12 AM3/5/20
to kivy-...@googlegroups.com

To Ticks I added the line below:

 

class Ticks(Widget):
   
def __init__(self, **kwargs):
       
super(Ticks, self).__init__(**kwargs)
       
self.bind(pos=self.update_clock)
       
self.bind(size=self
.update_clock)
        Clock.schedule_interval(
self.update_clock, 1)

 

I start the app and press:

I am a student

Time

Hour ßà Day

Interactive

 

Now I see an analog clock face ticking.

 

# kv = Builder.load_file("clockunit.kv")


class Ticks(Widget):
   
def __init__(self, **kwargs):
       
super(Ticks, self).__init__(**kwargs)
       
self.bind(pos=self.update_clock)
       
self.bind(size=self
.update_clock)
        Clock.schedule_interval(
self.update_clock, 1)

   
def update_clock(self, *args):
       
self.canvas.clear()
       
with self.canvas:
            time = datetime.datetime.now()
            Color(
0.2, 0.5, 0.2)
            Line(
points=[self.center_x, self.center_y, self.center_x+0.8*self.r*sin(pi/30*time.second), self.center_y+0.8*self.r*cos(pi/30*time.second)], width=1, cap="round")
            Color(
0.3, 0.6, 0.3)
            Line(
points=[self.center_x, self.center_y, self.center_x+0.7*self.r*sin(pi/30*time.minute), self.center_y+0.7*self.r*cos(pi/30*time.minute)], width=2, cap="round")
            Color(
0.4, 0.7, 0.4)
            th = time.hour*
60 + time.minute
            Line(
points=[self.center_x, self.center_y, self.center_x+0.5*self.r*sin(pi/360*th), self.center_y+0.5*self.r*cos(pi/360*th)], width=3, cap="round")


class MyTouch(Widget):
   
pass


class
MyMainApp(App):
    result = StringProperty(
"initialization")
   
#rect1.size = ObjectProperty(0,50)
    # rect2.size = ObjectProperty(0,50)

   
def build(self
):
       
return Builder.load_file("clockunit.kv")


if __name__ == "__main__":
    MyMainApp().run()

Prabhat K.C.

unread,
Mar 5, 2020, 4:07:34 PM3/5/20
to Kivy users support
Thank you so much. Worked perfect. You might know this better. Is there any widget similar to Kivy Calendar DatePicker which is available to use for python 3.7?

Elliot Garbus

unread,
Mar 5, 2020, 5:09:35 PM3/5/20
to kivy-...@googlegroups.com

I was under the impression that the Kivy Calendar  DatePicker works under Python3.   Do a google search I also recall seeing some forks on Github.  

--

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/b536c471-590b-486c-bb6a-1ec537512813%40googlegroups.com.

 

Prabhat K.C.

unread,
Mar 6, 2020, 12:05:40 PM3/6/20
to Kivy users support
I did actually try to implement it. I went to the Kivy Calendar package description after that and it says only for python 2.7. Thus was hoping if there was something else similar so I can show a flippable calendar I can change months and all.

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-...@googlegroups.com.

Elliot Garbus

unread,
Mar 6, 2020, 5:56:04 PM3/6/20
to kivy-...@googlegroups.com

The source code is here: https://bitbucket.org/xxblx/kivycalendar/src/master/KivyCalendar/

The last commit says Fixes for using Python3.  If the version from PyPI does not support Python3, just use the code at the link above.

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/d231f13c-a825-4786-90b0-88f37eafec93%40googlegroups.com.

 

Reply all
Reply to author
Forward
0 new messages