0
from tkinter import *
from tkcalendar import Calendar

def get_date():
    label.configure(text=str(today.get_displayed_month()))
    today.configure(day=str(today.get_date()))

 
win = Tk()
win.title('Calendar Picker')

label = Label(win,text='August 2020')
label.pack(pady=10)

btn = Button(win,text='Pick a date',command=get_date)
btn.pack(pady=10)

today = Calendar(win,selectmode='day',year=2020,month=8,day=6)
today.pack(pady=10)

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python38\lib\tkinter\__init__.py", line 1883, in __call__
    return self.func(*args)
  File "E:\Python\Python Projects Fun\calproject.py", line 6, in get_date
    today.configure(day=str(today.get_date()))
  File "C:\Python38\lib\site-packages\tkcalendar\calendar_.py", line 1612, in configure
    self[item] = value
  File "C:\Python38\lib\site-packages\tkcalendar\calendar_.py", line 518, in __setitem__
    raise AttributeError("Calendar object has no attribute %s." % key)
AttributeError: Calendar object has no attribute day.

Sorry when I pressed the button 'Pick a date' then the above error came out. May I ask what should I use if I want the corresponding date shown on top of the window when I move the months? Because I am not clear with the documentations so could someone teach me the method? What is the best way to fix the above error?

  • FYI `today.keys()` returns the list of keywords available in `.configure()`. If you want to change the currently selected day, use `today.selection_set(date)` though I don't understand why you want to set the currently selected date as the selected date. I think acw1668's answer is probably what you are looking for. If you want to ensure that the selected date is visible, then use `today.see(date)`. – j_4321 Aug 06 '20 at 07:52
  • @j_4321 I think what OP wants is that when the month is changed, he wants to highlight the same day as the previous month. – acw1668 Aug 06 '20 at 08:20

1 Answers1

3

The error is because day option is only available when you create the Calendar instance. It is not available in configure() function.

If you want to update the label whenever month is changed, you can bind on <<CalendarMonthChanged>> event and update the label inside the event callback:

def on_month_changed(event):
    month, year = today.get_displayed_month()
    label.configure(text=today._month_names[month]+' '+str(year))

...

today = Calendar(win, selectmode='day', year=2020, month=8, day=6)
today.pack(pady=10)
today.bind('<<CalendarMonthChanged>>', on_month_changed)

UPDATE: If you want to select the same day after the month is changed, modify the get_date() function as below:

import calendar
...
def get_date():
    month, year = today.get_displayed_month()
    # get the last day of selected month
    _, lastday = calendar.monthrange(year, month)
    # make sure day is valid day in selected month
    day = min(today._sel_date.day, lastday)
    # select the day in selected month
    today.selection_set(today.date(year, month, day))

UPDATE 2: Below is an example to update the calendar when a date is selected via tkcalendar.DateEntry:

from tkinter import *
from tkcalendar import Calendar, DateEntry

def date_selected(event):
    date = date_entry.get_date()
    cal.selection_set(date)
 
win = Tk()
win.title('Calendar Picker')

date_entry = DateEntry(win, date_pattern='y-mm-dd', state='readonly')
date_entry.pack()
date_entry.bind('<<DateEntrySelected>>', date_selected)

cal = Calendar(win, selectmode='day', date_pattern='y-mm-dd')
cal.pack(pady=10)

win.mainloop()
acw1668
  • 40,144
  • 5
  • 22
  • 34