Fading Coder

One Final Commit for the Last Sprint

Home > Tools > Content

Implementing a Chinese Numeral Clock with Python's Turtle Graphics

Tools 2

To create a Chinese numeral clock using Python's Turtle module, first install the necessary dependencies. On Debian-based systems, run:

sudo apt-get install python3-tk

The clock displays hours, minutes, and seconds as Chinese characters arranged in concentric circles, updated every second. The implementation uses three circles with numerals positioned around their circumference, centered on the current time.

import turtle
from datetime import datetime

def move_pen(steps):
    turtle.penup()
    turtle.forward(steps)
    turtle.pendown()

def draw_circle(labels, label_count, current_label, label_type, radius, offset, color, font_size):
    turtle.home()
    turtle.pensize(3)
    turtle.pencolor(color)
    turtle.fillcolor('#33BB00')
    
    move_pen(radius + offset + 30)
    turtle.write(label_type, align="center", font=("Courier", font_size, 'bold'))
    move_pen(-radius - offset - 30)
    
    start_index = labels.index(current_label)
    for idx in range(start_index, label_count):
        move_pen(radius)
        char_count = len(labels[idx])
        if idx == start_index:
            turtle.forward(75)
            turtle.backward(90)
            turtle.forward(15)
        for char_pos in range(char_count):
            turtle.write(labels[idx][char_pos], align="center", font=("Courier", font_size))
            turtle.forward(15)
        turtle.backward(15 * char_count)
        move_pen(-radius)
        turtle.left(360 / label_count)
    for idx in range(start_index):
        move_pen(radius)
        char_count = len(labels[idx])
        for char_pos in range(char_count):
            turtle.write(labels[idx][char_pos], align="center", font=("Courier", font_size))
            turtle.forward(15)
        turtle.backward(15 * char_count)
        move_pen(-radius)
        turtle.left(360 / label_count)

def get_weekday(date_obj):
    weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
    return weekdays[date_obj.weekday()]

def format_date(date_obj):
    return f"{date_obj.year}-{date_obj.month}-{date_obj.day}"

def update_clock():
    turtle.reset()
    now = datetime.now()
    second_val = now.second
    minute_val = now.minute
    hour_val = now.hour
    
    chinese_numerals = [' ', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十',
                        '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九',
                        '二十', '二十一', '二十二', '二十三', '二十四', '二十五', '二十六', '二十七', '二十八', '二十九',
                        '三十', '三十一', '三十二', '三十三', '三十四', '三十五', '三十六', '三十七', '三十八', '三十九',
                        '四十', '四十一', '四十二', '四十三', '四十四', '四十五', '四十六', '四十七', '四十八', '四十九',
                        '五十', '五十一', '五十二', '五十三', '五十四', '五十五', '五十六', '五十七', '五十八', '五十九']
    
    hour_labels = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十',
                   '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九',
                   '二十', '二十一', '二十二', '二十三', '二十四']
    
    draw_circle(chinese_numerals, len(chinese_numerals), chinese_numerals[second_val], '秒', 250, 25, 'blue', 10)
    draw_circle(chinese_numerals, len(chinese_numerals), chinese_numerals[minute_val], '分', 170, 20, 'green', 10)
    draw_circle(hour_labels, len(hour_labels), hour_labels[hour_val - 1], '时', 80, 15, 'red', 10)
    
    text_turtle = turtle.Turtle()
    text_turtle.hideturtle()
    text_turtle.color('#11CCFF')
    text_turtle.right(-90)
    text_turtle.penup()
    text_turtle.forward(40)
    text_turtle.write(get_weekday(now), align="center", font=("Courier", 10, "bold"))
    text_turtle.backward(80)
    text_turtle.write(format_date(now), align="center", font=("Courier", 14, "bold"))
    text_turtle.right(90)
    turtle.ontimer(update_clock, 1000)

def main():
    turtle.tracer(False)
    screen = turtle.getscreen()
    screen.bgcolor("black")
    update_clock()
    turtle.mainloop()

if __name__ == "__main__":
    main()

Key Turtle methods used in this implementation include:

  • forward(distance) / backward(distance): Move the turtle forward or backward.
  • right(angle) / left(angle): Rotate the turtle right or left by specified degrees.
  • penup() / pendown(): Lift or lower the pen for drawing.
  • write(text, align, font): Display text on the screen.
  • home(): Return the turtle to the origin.
  • ontimer(func, delay): Schedule a function to run after a delay.
  • tracer(enable): Control animation updates.
  • hideturtle(): Hide the turtle cursor.
  • pencolor(color) / fillcolor(color): Set drawing and fill colors.
  • pensize(width): Adjust line thickness.
  • reset(): Clear the screen and reset turtle state.
  • mainloop(): Start the event loop.

For a standard analog clock implemantation with Turtle, consider this alternative approach:

import turtle
from datetime import datetime

def create_hand(name, length):
    turtle.reset()
    turtle.penup()
    turtle.backward(length * 0.1)
    turtle.pendown()
    turtle.begin_poly()
    turtle.forward(length * 1.1)
    turtle.end_poly()
    hand_shape = turtle.get_poly()
    turtle.register_shape(name, hand_shape)

def initialize_clock():
    turtle.mode("logo")
    create_hand("second_hand", 135)
    create_hand("minute_hand", 125)
    create_hand("hour_hand", 90)
    
    second_hand = turtle.Turtle()
    second_hand.shape("second_hand")
    minute_hand = turtle.Turtle()
    minute_hand.shape("minute_hand")
    hour_hand = turtle.Turtle()
    hour_hand.shape("hour_hand")
    
    for hand in [second_hand, minute_hand, hour_hand]:
        hand.shapesize(1, 1, 3)
        hand.speed(0)
    
    return second_hand, minute_hand, hour_hand

def draw_clock_face(radius):
    turtle.reset()
    turtle.pensize(7)
    turtle.pencolor("#ff5500")
    turtle.fillcolor("green")
    
    for i in range(60):
        turtle.penup()
        turtle.forward(radius)
        turtle.pendown()
        if i % 5 == 0:
            turtle.forward(20)
            turtle.penup()
            turtle.backward(radius + 20)
            turtle.forward(radius + 20)
            if i == 0:
                turtle.write("12", align="center", font=("Courier", 14, "bold"))
            else:
                turtle.write(str(i // 5), align="center", font=("Courier", 14, "bold"))
            turtle.backward(radius + 20)
        else:
            turtle.dot(5)
            turtle.penup()
            turtle.backward(radius)
        turtle.right(6)

def update_analog_clock(second_hand, minute_hand, hour_hand):
    current_time = datetime.now()
    second = current_time.second + current_time.microsecond * 0.000001
    minute = current_time.minute + second / 60.0
    hour = current_time.hour + minute / 60.0
    
    second_hand.setheading(6 * second)
    minute_hand.setheading(6 * minute)
    hour_hand.setheading(30 * hour)
    
    turtle.ontimer(lambda: update_analog_clock(second_hand, minute_hand, hour_hand), 100)

def run_analog_clock():
    turtle.tracer(False)
    screen = turtle.getscreen()
    screen.bgcolor("#BBBBBB")
    second_hand, minute_hand, hour_hand = initialize_clock()
    draw_clock_face(160)
    turtle.tracer(True)
    update_analog_clock(second_hand, minute_hand, hour_hand)
    turtle.mainloop()

if __name__ == "__main__":
    run_analog_clock()

Related Articles

Efficient Usage of HTTP Client in IntelliJ IDEA

IntelliJ IDEA incorporates a versatile HTTP client tool, enabling developres to interact with RESTful services and APIs effectively with in the editor. This functionality streamlines workflows, replac...

Installing CocoaPods on macOS Catalina (10.15) Using a User-Managed Ruby

System Ruby on macOS 10.15 frequently fails to build native gems required by CocoaPods (for example, ffi), leading to errors like: ERROR: Failed to build gem native extension checking for ffi.h... no...

Resolve PhpStorm "Interpreter is not specified or invalid" on WAMP (Windows)

Symptom PhpStorm displays: "Interpreter is not specified or invalid. Press ‘Fix’ to edit your project configuration." This occurs when the IDE cannot locate a valid PHP CLI executable or when the debu...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.