14

私はKivyが初めてで、フレームワークのいくつかの基本だけでなく、イベントをより適切に処理しようとしています。

その目的のために、現在の時刻を表示し、毎秒更新する、Kivy に実装された単純な時計のコードを誰でも提供できますか?

4

2 に答える 2

49

単純なグラフィカルなものはどうですか:

ここに画像の説明を入力 編集 (12.02.2022) : コード全体をリファクタリングして読みやすくしました

import collections
import datetime
import math

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.graphics import Color, Line

Builder.load_string('''
<MyClockWidget>:
    on_pos: self.update_clock()
    on_size: self.update_clock()
    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
    FloatLayout
        id: hands
        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)
''')

Position = collections.namedtuple('Position', 'x y')


class MyClockWidget(FloatLayout):
    def on_parent(self, myclock, parent):
        """
        Add number labels when added in widget hierarchy
        """
        for i in range(1, 13):
            number = Label(
                text=str(i),
                pos_hint={
                    # pos_hint is a fraction in range (0, 1)
                    "center_x": 0.5 + 0.45*math.sin(2 * math.pi * i/12),
                    "center_y": 0.5 + 0.45*math.cos(2 * math.pi * i/12),
                }
            )
            self.ids["face"].add_widget(number)

    def position_on_clock(self, fraction, length):
        """
        Calculate position in the clock using trygonometric functions
        """
        center_x = self.size[0]/2
        center_y = self.size[1]/2
        return Position(
            center_x + length * math.sin(2 * math.pi * fraction),
            center_y + length * math.cos(2 * math.pi * fraction),
        )

    def update_clock(self, *args):
        """
        Redraw clock hands
        """
        time = datetime.datetime.now()
        hands = self.ids["hands"]
        seconds_hand = self.position_on_clock(time.second/60, length=0.45*hands.size[0])
        minutes_hand = self.position_on_clock(time.minute/60+time.second/3600, length=0.40*hands.size[0])
        hours_hand = self.position_on_clock(time.hour/12 + time.minute/720, length=0.35*hands.size[0])

        hands.canvas.clear()
        with hands.canvas:
            Color(0.2, 0.5, 0.2)
            Line(points=[hands.center_x, hands.center_y, seconds_hand.x, seconds_hand.y], width=1, cap="round")
            Color(0.3, 0.6, 0.3)
            Line(points=[hands.center_x, hands.center_y, minutes_hand.x, minutes_hand.y], width=2, cap="round")
            Color(0.4, 0.7, 0.4)
            Line(points=[hands.center_x, hands.center_y, hours_hand.x, hours_hand.y], width=3, cap="round")


class MyApp(App):
    def build(self):
        clock_widget = MyClockWidget()
        # update initially, just after construction of the widget is complete
        Clock.schedule_once(clock_widget.update_clock, 0)
        # then update every second
        Clock.schedule_interval(clock_widget.update_clock, 1)
        return clock_widget


if __name__ == '__main__':
    MyApp().run()

古い答え:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Line
from kivy.uix.floatlayout import FloatLayout
from math import cos, sin, pi
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import NumericProperty

import datetime

kv = '''
#:import math math

[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

<MyClockWidget>:
    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
'''
Builder.load_string(kv)

class MyClockWidget(FloatLayout):
    pass

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 MyClockApp(App):
    def build(self):
        clock = MyClockWidget()
        Clock.schedule_interval(clock.ticks.update_clock, 1)
        return clock

if __name__ == '__main__':
    MyClockApp().run()
于 2013-09-21T21:46:50.730 に答える