You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Tkinter、Schedule与Threading实现日历每日自动更新的技术问题求助

解决tkcalendar每日自动更新的问题

你的代码主要有几个问题导致日历无法自动更新:

  • schedule.run_all()只会立刻执行一次任务,不会持续监听后续的定时触发,因为root.mainloop()会阻塞主线程,schedule的任务循环没法运行。
  • 用子线程操作tkinter组件是不安全的,tkinter要求所有GUI操作必须在主线程执行,否则可能导致崩溃或异常。
  • job2里没有实际更新Calendar组件的逻辑。

下面提供两种可靠的解决方案,优先推荐第一种(适配tkinter的原生定时方式):

方案一:使用tkinter的after方法(推荐)

tkinter自带的after方法可以在主线程中安全地执行定时任务,完美适配GUI操作。我们只需要计算当前时间到下一个午夜的时间差,然后设置定时更新日历即可:

from tkinter import *
from tkcalendar import Calendar
import datetime

root = Tk()
box = Frame(root, width=500, height=550, highlightbackground="red", highlightthickness=5)
box.grid(row=0, column=1)
root.geometry('1000x500')

# 初始化日历组件
crm = Calendar(root, firstweekday='sunday', selectmode='none', showweeknumbers=False, 
               font=('Helvetica',15, 'bold'), fill='both', expand=True)
crm.grid(ipady=110, ipadx=250, row=0, column=0)

def update_calendar():
    # 将日历选中并刷新到当前日期
    crm.selection_set(datetime.date.today())
    print("日历已更新为今日日期")
    
    # 计算距离下一个午夜的时间差(转换为毫秒)
    now = datetime.datetime.now()
    next_midnight = datetime.datetime(now.year, now.month, now.day) + datetime.timedelta(days=1)
    time_diff_ms = int((next_midnight - now).total_seconds() * 1000)
    
    # 设置下一次更新的定时任务
    root.after(time_diff_ms, update_calendar)

# 启动首次更新并设置循环定时
update_calendar()

root.mainloop()

这个方案的优势:

  • 所有操作都在主线程,完全符合tkinter的线程安全要求
  • 精确计算到下一个午夜的时间,不会有误差
  • selection_set方法不仅会选中当前日期,还会自动刷新月份显示(如果跨月的话)

方案二:结合schedule库使用

如果你坚持要用schedule库,需要在主线程中定期调用schedule.run_pending()来检查任务是否到了执行时间,同样不能用子线程操作GUI:

from tkinter import *
import schedule
import datetime
from tkcalendar import Calendar

root = Tk()
box = Frame(root, width=500, height=550, highlightbackground="red", highlightthickness=5)
box.grid(row=0, column=1)
root.geometry('1000x500')

crm = Calendar(root, firstweekday='sunday', selectmode='none', showweeknumbers=False, 
               font=('Helvetica',15, 'bold'), fill='both', expand=True)
crm.grid(ipady=110, ipadx=250, row=0, column=0)

def update_calendar():
    # 更新日历到当前日期
    crm.selection_set(datetime.date.today())
    print("午夜已至,日历已更新")

# 定义每日午夜的定时任务
schedule.every().day.at("00:00").do(update_calendar)

def check_schedule():
    # 检查是否有待执行的schedule任务
    schedule.run_pending()
    # 每隔1秒检查一次,确保任务不会遗漏
    root.after(1000, check_schedule)

# 启动schedule检查循环
check_schedule()

root.mainloop()

这个方案需要注意:

  • 必须用after循环在主线程中调用schedule.run_pending(),不能单独开子线程跑schedule的循环
  • 每隔1秒检查一次的频率足够低,不会影响GUI性能

内容的提问来源于stack exchange,提问作者RM2020

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 13:54:09