基于Python打造一个你的专属中医养生桌面时钟

 更新时间:2026年01月21日 08:36:33   作者:幸福清风  
这篇文章主要和大家详细介绍了一个有趣又有用的小项目,即使用 Python 编写一个集成了公历、农历和中医十二时辰养生提示的桌面时钟,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下

今天想和大家分享一个有趣又有用的小项目——如何使用 Python 编写一个集成了公历、农历和中医十二时辰养生提示的桌面时钟。这个项目不仅实用,还能让我们在快节奏的生活中,偶尔抬头看看屏幕,就能得到一份来自古老智慧的关怀。

效果展示

项目背景与灵感

随着生活节奏的加快,越来越多的人开始关注健康和养生。中医的“十二时辰养生法”是古人根据人体经络气血运行规律总结出的经验,比如“卯时(5-7点)大肠经当令,适合起床喝水促进排毒”。将这些知识融入到一个实时更新的时钟中,既能满足我们查看时间的基本需求,又能随时提醒我们顺应自然规律调养身体,岂不是很棒?

技术实现详解

我们的“中医养生时钟”主要依赖以下几个 Python 库:

  • tkinter: Python 自带的 GUI 库,用于构建图形用户界面。
  • datetime: Python 标准库,用于获取和格式化当前时间。
  • lunardate: 一个第三方库,专门用来处理农历日期转换。需要先通过 pip install lunardate 安装。

1. 核心类ChineseClock

整个程序围绕 ChineseClock 类展开。它的 __init__ 方法负责初始化所有数据和 UI 组件。

数据准备

  • shichen_dict: 这是一个核心字典,存储了十二时辰、对应的时间范围(24小时制)以及对应的养生提示。键是一个元组 (时辰名, 时间范围),值是提示字符串。
  • lunar_months: 一个列表,将数字月份映射为农历月份名称(如 ["正月", "二月", ...]),方便后续显示。

用户界面 (create_widgets)

我们创建了一个无边框 (overrideredirect) 并始终置顶 (attributes('-topmost', True)) 的窗口,使其像一个小工具一样常驻屏幕。

布局: 使用 tk.Frame 作为主容器 (main_frame),内部元素垂直堆叠 (pack)。

组件:

  • gregorian_label: 显示完整的公历年月日时分秒。
  • weekday_label: 显示星期几。
  • lunar_label: 显示农历日期。
  • shichen_label: 显示当前时辰及其养生提示。
  • close_button: 一个简洁的“×”号按钮,放在窗口右上角,用于关闭程序。
  • 样式: 设置了不同的字体大小、颜色和背景色,使其看起来更美观、信息层次分明。例如,公历时间用绿色,星期用黄色,农历用金色,时辰提示用红色。

功能函数

  • get_lunar_date(): 调用 LunarDate.fromSolarDate 获取今天的农历日期对象。然后处理月份(包括闰月)和日期(通过 number_to_chinese 函数将数字转换为“初一”、“初二”等)的格式化,最终返回如“农历:二零二六年正月初一”的字符串。
  • get_shichen(): 获取当前小时 (datetime.now().hour),遍历 shichen_dict,判断当前小时落在哪个时辰范围内。特别注意处理跨天的“子时”(23:00-01:00)。找到后返回格式化的提示信息,如“子时(23:00-01:00)· 胆经运行,及时入睡养阳气”。
  • update_time(): 这是驱动时钟的核心函数。它:
    • 获取当前时间 (now)。
    • 更新公历、星期、农历标签的文本。
    • 调用 get_shichen 更新时辰提示。
    • 使用 self.root.after(1000, self.update_time) 递归调用自身,实现每秒刷新一次显示。

可拖动窗口 (bind_drag_events,start_drag,on_drag)

为了让时钟可以随意移动到屏幕的任意位置,我们实现了窗口拖动功能。

  • 我们为 main_frame 内的所有子组件(除了 close_button)以及 root 窗口本身绑定了鼠标事件 <ButtonPress-1><B1-Motion>
  • start_drag: 记录鼠标按下的初始坐标(相对于被点击组件的位置)。
  • on_drag: 当鼠标拖动时,计算窗口的新位置(winfo_x + 鼠标移动的偏移量),并用 geometry 方法更新窗口位置。
  • 通过检查 event.widget 是否为 close_button,我们确保在关闭按钮上按住时不会触发拖动,保证按钮功能正常。

2. 程序入口

if __name__ == "__main__": 语句块创建 ChineseClock 实例,并启动 Tkinter 的事件循环 mainloop(),程序开始运行并等待用户交互。

完整代码

import tkinter as tk
from datetime import datetime
from lunardate import LunarDate


class ChineseClock:
    def __init__(self):
        # 时辰养生提示字典
        self.shichen_dict = {
            ("子时", "23:00-01:00"): "胆经运行,及时入睡养阳气",
            ("丑时", "01:00-03:00"): "肝经运行,深度睡眠助排毒",
            ("寅时", "03:00-05:00"): "肺经运行,保持温暖忌寒凉",
            ("卯时", "05:00-07:00"): "大肠经运行,起床饮水促排毒",
            ("辰时", "07:00-09:00"): "胃经运行,营养早餐要温食",
            ("巳时", "09:00-11:00"): "脾经运行,适当活动助运化",
            ("午时", "11:00-13:00"): "心经运行,小憩养神忌过劳",
            ("未时", "13:00-15:00"): "小肠经运行,补充水分助吸收",
            ("申时", "15:00-17:00"): "膀胱经运行,多喝温水促代谢",
            ("酉时", "17:00-19:00"): "肾经运行,少盐饮食护肾气",
            ("戌时", "19:00-21:00"): "心包经运行,放松心情宜休闲",
            ("亥时", "21:00-23:00"): "三焦经运行,准备入睡排烦恼"
        }

        # 农历月份转换
        self.lunar_months = ["正月", "二月", "三月", "四月", "五月", "六月",
                             "七月", "八月", "九月", "十月", "冬月", "腊月"]

        # 创建主窗口
        self.root = tk.Tk()
        self.root.title("中医养生时钟")
        self.root.attributes('-topmost', True)
        self.root.overrideredirect(True)  # 无边框窗口
        self.root.config(bg='black')

        # 拖动相关变量
        self._drag_start_x = 0
        self._drag_start_y = 0

        # 创建界面组件
        self.create_widgets()

        # 绑定拖动事件
        self.bind_drag_events()

        # 初始位置
        self.set_initial_position()

        # 启动时间更新
        self.update_time()

    def close_window(self):
        """关闭窗口的方法"""
        print("正在关闭时钟...")
        self.root.destroy()

    def bind_drag_events(self):
        """
        为窗口主体内容绑定拖动事件。
        避免对关闭按钮等特定组件绑定拖动事件,以确保它们能被正常点击。
        """
        # 对于 main_frame 内的每个子组件
        for child in self.main_frame.winfo_children():
            # 如果不是关闭按钮,则绑定拖动事件
            if child != self.close_button:
                child.bind("<ButtonPress-1>", self.start_drag)
                child.bind("<B1-Motion>", self.on_drag)

        # 主窗口本身也可以拖动(只要不在关闭按钮上按下的情况下)
        self.root.bind("<ButtonPress-1>", self.start_drag)
        self.root.bind("<B1-Motion>", self.on_drag)

    def start_drag(self, event):
        """记录拖动起始位置,但排除在关闭按钮上的操作"""
        # 检查事件是否发生在关闭按钮上
        if str(event.widget) == str(self.close_button):
            # 如果在关闭按钮上按下,则不进行任何拖动相关的操作
            return
        # 否则,记录拖动的初始相对位置(相对于被点击的widget)
        self._drag_start_x = event.x
        self._drag_start_y = event.y

    def on_drag(self, event):
        """处理拖动事件"""
        x = self.root.winfo_x() + (event.x - self._drag_start_x)
        y = self.root.winfo_y() + (event.y - self._drag_start_y)
        self.root.geometry(f"+{x}+{y}")

    def set_initial_position(self):
        """设置初始位置在右上角"""
        screen_width = self.root.winfo_screenwidth()
        self.root.geometry(f"+{screen_width - 600}+20")

    def create_widgets(self):
        """创建界面组件"""
        # 字体配置
        time_font = ('微软雅黑', 26, 'bold')  # 公历时间
        weekday_font = ('微软雅黑', 22, 'bold')  # 星期
        lunar_font = ('微软雅黑', 18)  # 农历
        shichen_font = ('微软雅黑', 16)  # 时辰提示

        # 创建一个Frame来容纳主要内容
        self.main_frame = tk.Frame(self.root, bg='black')
        self.main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 关闭按钮 - 优化版
        # 使用较小的尺寸,避免遮挡文本
        self.close_button = tk.Button(
            self.root,
            text="×",
            command=self.close_window,
            font=('Arial', 6, 'bold'),  # 更清晰的字体
            fg='white',
            bg='red',
            bd=0,
            width=1,
            height=1,
            relief='flat'  # 去除按钮立体感
        )
        # 精确放置:x=-15, y=10 使按钮更靠近右上角,且不遮挡时间
        self.close_button.place(relx=1.0, rely=0.0, anchor='ne', x=-2, y=2)

        # 公历时间标签
        self.gregorian_label = tk.Label(
            self.main_frame,
            font=time_font,
            fg='#00FF00',  # 绿色
            bg='black'
        )
        self.gregorian_label.pack(pady=(0, 5))

        # 星期标签
        self.weekday_label = tk.Label(
            self.main_frame,
            font=weekday_font,
            fg='#FFFF00',  # 黄色
            bg='black'
        )
        self.weekday_label.pack(pady=(0, 10))

        # 农历时间标签
        self.lunar_label = tk.Label(
            self.main_frame,
            font=lunar_font,
            fg='#FFD700',  # 金色
            bg='black'
        )
        self.lunar_label.pack(pady=(0, 10))

        # 时辰提示标签
        self.shichen_label = tk.Label(
            self.main_frame,
            font=shichen_font,
            fg='#FF6347',  # 深红
            bg='black',
            wraplength=400,  # 文本自动换行
            justify='center'  # 居中对齐
        )
        self.shichen_label.pack(pady=(0, 10))

        # 添加底部装饰线(可选)
        separator = tk.Frame(self.main_frame, height=2, bg='#333333', width=400)
        separator.pack(pady=(0, 5))

    def get_shichen(self):
        """获取当前时辰及提示"""
        current_hour = datetime.now().hour
        for (name, time_range), tip in self.shichen_dict.items():
            start = int(time_range.split("-")[0].split(":")[0])
            end = int(time_range.split("-")[1].split(":")[0])
            # 处理跨天时辰(子时)
            if start > end:
                if current_hour >= start or current_hour < end:
                    return f"{name}({time_range})· {tip}"
            elif start <= current_hour < end:
                return f"{name}({time_range})· {tip}"
        return ""

    def get_lunar_date(self):
        """获取格式化农历日期"""
        now = datetime.now()
        lunar_date = LunarDate.fromSolarDate(now.year, now.month, now.day)

        # 转换月份
        month_str = self.lunar_months[lunar_date.month - 1]
        if lunar_date.isLeapMonth:
            month_str = "闰" + month_str

        # 转换日期
        day_str = self.number_to_chinese(lunar_date.day)

        return f"农历:{lunar_date.year}年{month_str}{day_str}"

    def number_to_chinese(self, num):
        """数字转中文日期(1-30)"""
        chinese_days = ["初一", "初二", "初三", "初四", "初五",
                        "初六", "初七", "初八", "初九", "初十",
                        "十一", "十二", "十三", "十四", "十五",
                        "十六", "十七", "十八", "十九", "二十",
                        "廿一", "廿二", "廿三", "廿四", "廿五",
                        "廿六", "廿七", "廿八", "廿九", "三十"]
        return chinese_days[num - 1]

    def update_time(self):
        """更新时间显示"""
        now = datetime.now()

        # 公历时间
        gregorian_text = now.strftime(f"北京时间:%Y-%m-%d %H:%M:%S")
        self.gregorian_label.config(text=gregorian_text)

        # 星期
        weekdays_zh = ["星期一", "星期二", "星期三",
                       "星期四", "星期五", "星期六", "星期日"]
        weekday_str = weekdays_zh[now.weekday()]
        self.weekday_label.config(text=weekday_str)

        # 农历时间
        self.lunar_label.config(text=self.get_lunar_date())

        # 时辰提示
        self.shichen_label.config(text=self.get_shichen())

        # 每秒更新
        self.root.after(1000, self.update_time)


if __name__ == "__main__":
    clock = ChineseClock()
    clock.root.mainloop()

到此这篇关于基于Python打造一个你的专属中医养生桌面时钟的文章就介绍到这了,更多相关Python桌面时钟内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python classmethod装饰器原理及用法解析

    Python classmethod装饰器原理及用法解析

    这篇文章主要介绍了Python classmethod装饰器原理及用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • python 异常捕获详解流程

    python 异常捕获详解流程

    异常即非正常状态,在Python中使用异常对象来表示异常。若程序在编译或运行过程中发生错误,程序的执行过程就会发生改变,抛出异常对象,程序流进入异常处理。如果异常对象没有被处理或捕捉,程序就会执行回溯(Traceback)来终止程序
    2022-03-03
  • python无法识别vim中文代码的解决方案

    python无法识别vim中文代码的解决方案

    这篇文章主要介绍了python无法识别vim中文代码的解决方案,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-03-03
  • python Scala函数与访问修辞符实例详解

    python Scala函数与访问修辞符实例详解

    这篇文章主要为大家介绍了python Scala函数与访问修辞符实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • Python中实现switch功能实例解析

    Python中实现switch功能实例解析

    这篇文章主要介绍了Python中实现switch功能实例解析,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01
  • 初步介绍Python中的pydoc模块和distutils模块

    初步介绍Python中的pydoc模块和distutils模块

    这篇文章主要介绍了Python中的pydoc模块和distutils模块,本文来自于IBM官方开发者技术文档,需要的朋友可以参考下
    2015-04-04
  • pandas中NaN缺失值的处理方法

    pandas中NaN缺失值的处理方法

    当我们用python进行数据处理时会遇到很多缺失值,对缺失值我们需要进行删除或者填补,本文主要介绍了pandas中NaN缺失值的处理方法,感兴趣的可以了解一下
    2021-05-05
  • 详解在Python程序中解析并修改XML内容的方法

    详解在Python程序中解析并修改XML内容的方法

    这篇文章主要介绍了在Python程序中解析并修改XML内容的方法,依赖于解析成树状结构后的节点进行修改,需要的朋友可以参考下
    2015-11-11
  • Python使用pip通过命令设置国内镜像源的三种方式

    Python使用pip通过命令设置国内镜像源的三种方式

    在使用 pip 安装 Python 模块时,默认的国外镜像源可能会导致下载速度缓慢甚至超时,为了解决这个问题,可以使用国内的镜像源来加速下载,以下是常用的国内镜像源以及临时和永久的配置方法,需要的朋友可以参考下
    2025-08-08
  • Python中的列表知识点汇总

    Python中的列表知识点汇总

    这篇文章主要总结了一些Python中的列表的知识点,来自于IBM官网技术文档,需要的朋友可以参考下
    2015-04-04

最新评论