
效果图如下:
代码如下:
import tkinter as tk
from math import pi, sin, cos
from datetime import datetime
class AnalogClock:
def __init__(self, master):
self.master = master
self.master.overrideredirect(True) # 去掉窗口的标题栏和默认按钮
self.master.geometry("400x400") # 设置初始窗口大小
self.master.resizable(True, True) # 允许窗口调整大小
# 创建右键菜单
self.context_menu = tk.Menu(self.master, tearoff=0)
self.context_menu.add_***mand(label="放大", ***mand=self.zoom_in)
self.context_menu.add_***mand(label="缩小", ***mand=self.zoom_out)
self.context_menu.add_***mand(label="关闭", ***mand=self.close_window)
# 绑定右键菜单事件
self.master.bind("<Button-3>", self.show_context_menu)
# 绑定窗口大小变化事件
self.master.bind("<Configure>", self.on_resize)
# 绑定鼠标事件以实现窗口拖动
self.master.bind("<Button-1>", self.start_drag) # 鼠标左键按下
self.master.bind("<B1-Motion>", self.drag_window) # 鼠标左键拖动
self.master.bind("<ButtonRelease-1>", self.stop_drag) # 鼠标左键释放
# 拖动相关的变量
self.drag_data = {"x": 0, "y": 0, "dragging": False}
# 创建画布
self.canvas = tk.Canvas(master, bg='white', highlightthickness=0)
self.canvas.pack(expand=tk.YES, fill=tk.BOTH)
# 初始绘制
self.on_resize()
def show_context_menu(self, event):
"""显示右键菜单"""
self.context_menu.post(event.x_root, event.y_root)
def zoom_in(self):
"""放大窗口, 每次放大10%"""
current_width = self.master.winfo_width()
current_height = self.master.winfo_height()
new_width = int(current_width * 1.1) # 放大10%
new_height = int(current_height * 1.1) # 放大10%
self.master.geometry(f"{new_width}x{new_height}") # 设置窗口大小为500x500
def zoom_out(self):
"""缩小窗口, 每次缩小10%"""
current_width = self.master.winfo_width()
current_height = self.master.winfo_height()
new_width = int(current_width * 0.9) # 缩小10%
new_height = int(current_height * 0.9) # 缩小10%
self.master.geometry(f"{new_width}x{new_height}") # 设置窗口大小为500x500
def close_window(self):
"""关闭窗口"""
self.master.destroy() # 关闭窗口
def start_drag(self, event):
"""记录鼠标按下时的初始位置"""
self.drag_data["x"] = event.x
self.drag_data["y"] = event.y
self.drag_data["dragging"] = True
def drag_window(self, event):
"""拖动窗口"""
if self.drag_data["dragging"]:
# 计算窗口的新位置
x = self.master.winfo_x() + (event.x - self.drag_data["x"])
y = self.master.winfo_y() + (event.y - self.drag_data["y"])
self.master.geometry(f"+{x}+{y}") # 设置窗口的新位置
def stop_drag(self, event):
"""停止拖动"""
self.drag_data["dragging"] = False
def on_resize(self, event=None):
"""窗口大小改变时重新绘制时钟"""
# 获取当前画布尺寸
self.width = self.canvas.winfo_width()
self.height = self.canvas.winfo_height()
# 计算时钟参数
self.radius = min(self.width, self.height) * 0.48 # 半径为窗口较小尺寸的48%
self.center_x = self.width // 2
self.center_y = self.height // 2
# 清除画布并重新绘制
self.canvas.delete("all")
self.draw_clock_face()
self.update_time()
def draw_clock_face(self):
"""绘制钟面"""
# 设置钟面的边框
self.canvas.create_oval(
self.center_x - self.radius,
self.center_y - self.radius,
self.center_x + self.radius,
self.center_y + self.radius,
fill="#f2f2f2",
outline="#99ffbb", width=4
)
a1 = self.radius-self.radius*0.05
self.canvas.create_oval(
self.center_x - a1,
self.center_y - a1,
self.center_x + a1,
self.center_y + a1,
fill="#99ffbb",
outline="#99ffbb", width=4
)
# 绘制刻度线和数字
for i in range(60):
angle = i * (2 * pi / 60) - pi / 2 # 将角度转换为弧度,并调整起始位置(从12点开始)
if i % 5 == 0: # 每5分钟有一个较长的刻度
length = self.radius * 0.05 # 刻度长度按比例计算
# 数字标签的角度应与刻度线角度一致
hour_num = (i // 5) % 12
hour_num = 12 if hour_num == 0 else hour_num # 将0点显示为12
text_radius = self.radius * 0.85 # 数字离中心距离按比例计算
x = self.center_x + text_radius * cos(angle)
y = self.center_y + text_radius * sin(angle)
font_size = max(10, int(self.radius * 0.15)) # 字体大小按比例计算
self.canvas.create_text(x, y, text=str(hour_num),font=("Helvetica", font_size, "bold"))
else:
length = self.radius * 0.025 # 短刻度长度
x1 = self.center_x + (self.radius - length) * cos(angle)
y1 = self.center_y + (self.radius - length) * sin(angle)
x2 = self.center_x + self.radius * cos(angle)
y2 = self.center_y + self.radius * sin(angle)
self.canvas.create_line(x1, y1, x2, y2, fill='#00995c', width=2 if i % 5 == 0 else 1)
# 中心点装饰
dot_size = max(3, self.radius * 0.02) # 中心点大小按比例计算
self.canvas.create_oval(
self.center_x - dot_size,
self.center_y - dot_size,
self.center_x + dot_size,
self.center_y + dot_size,
fill='black'
)
def update_time(self):
"""获取当前时间并更新指针位置"""
now = datetime.now()
hour = now.hour % 12
minute = now.minute
second = now.second
# 计算每个指针的角度
hour_angle = (hour + minute / 60) * (pi / 6) - pi / 2
minute_angle = (minute + second / 60) * (pi / 30) - pi / 2
second_angle = second * (pi / 30) - pi / 2
# 删除旧的指针
self.canvas.delete("hand")
# 更新日期显示
self.update_date_display()
# 绘制新的指针
self.draw_hand(hour_angle, length=self.radius * 0.5, color='#0033***', width=self.radius * 0.02)
self.draw_hand(minute_angle, length=self.radius * 0.7, color='#0000***', width=self.radius * 0.015)
self.draw_hand(second_angle, length=self.radius * 0.8, color='red', width=self.radius * 0.01)
# 每隔一秒重新绘制一次
self.master.after(1000, self.update_time)
def update_date_display(self):
"""更新日期和星期显示"""
# 格式化日期和星期
now = datetime.now()
date_str = now.strftime("%Y年%m月%d日")
weekday_str = now.strftime("星期%a")
# 删除旧内容(通过标签精准定位)
self.canvas.delete("date", "weekday")
# 星期转换为中文
weekday_map = {
"Mon": "一", "Tue": "二", "Wed": "三",
"Thu": "四", "Fri": "五", "Sat": "六", "Sun": "日"
}
for eng, chn in weekday_map.items():
weekday_str = weekday_str.replace(eng, chn)
# 计算字体大小
font_size = max(10, int(self.radius * 0.1))
# 创建日期和星期标签
self.canvas.create_text(
self.center_x, self.center_y - self.radius * 0.2,
text=date_str, font=("Helvetica", font_size, "bold"),
tags="date"
)
self.canvas.create_text(
self.center_x, self.center_y + self.radius * 0.2,
text=weekday_str, font=("Helvetica", font_size, "bold"),
tags="weekday"
)
def draw_hand(self, angle, length, color, width):
"""根据给定的角度和长度绘制指针"""
end_x = self.center_x + length * cos(angle)
end_y = self.center_y + length * sin(angle)
return self.canvas.create_line(
self.center_x, self.center_y,
end_x, end_y,
fill=color, width=max(1, int(width)), # 确保最小线宽为1
tags="hand"
)
if __name__ == "__main__":
root = tk.Tk()
root.title("可缩放模拟时钟")
root.attributes("-transparentcolor", "white") # 设置透明背景颜色
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
window_width = 400
window_height = 400
# 计算窗口位置
x_position = screen_width - window_width - 100 # 距离右边 100 像素
y_position = 50 # 距离上边 50 像素
# 设置窗口初始位置和大小
root.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}")
clock = AnalogClock(root)
root.mainloop()