Is it possible to embed custom text in python tkcalendar's date
It is not possible from tkcalendar's methods to display text below the day number in the Calendar. However, you don't have to start from scratch, you can create an Agenda
class inheriting from Calendar
and only rewrite the methods displaying the events to put them inside the day's label instead of in a popup.
To be precise, 3 methods need to be modified: _display_days_without_othermonthdays()
, _display_days_with_othermonthdays()
and _show_event()
, see code below. The code might seem long but I actually only modified a couple of lines in each methods compared to there original version in tkcalendar.
from tkcalendar import Calendarclass Agenda(Calendar): def __init__(self, master=None, **kw): Calendar.__init__(self, master, **kw) # change a bit the options of the labels to improve display for i, row in enumerate(self._calendar): for j, label in enumerate(row): self._cal_frame.rowconfigure(i + 1, uniform=1) self._cal_frame.columnconfigure(j + 1, uniform=1) label.configure(justify="center", anchor="n", padding=(1, 4)) def _display_days_without_othermonthdays(self): year, month = self._date.year, self._date.month cal = self._cal.monthdays2calendar(year, month) while len(cal) < 6: cal.append([(0, i) for i in range(7)]) week_days = {i: 'normal.%s.TLabel' % self._style_prefixe for i in range(7)} # style names depending on the type of day week_days[self['weekenddays'][0] - 1] = 'we.%s.TLabel' % self._style_prefixe week_days[self['weekenddays'][1] - 1] = 'we.%s.TLabel' % self._style_prefixe _, week_nb, d = self._date.isocalendar() if d == 7 and self['firstweekday'] == 'sunday': week_nb += 1 modulo = max(week_nb, 52) for i_week in range(6): if i_week == 0 or cal[i_week][0][0]: self._week_nbs[i_week].configure(text=str((week_nb + i_week - 1) % modulo + 1)) else: self._week_nbs[i_week].configure(text='') for i_day in range(7): day_number, week_day = cal[i_week][i_day] style = week_days[i_day] label = self._calendar[i_week][i_day] label.state(['!disabled']) if day_number: txt = str(day_number) label.configure(text=txt, style=style) date = self.date(year, month, day_number) if date in self._calevent_dates: ev_ids = self._calevent_dates[date] i = len(ev_ids) - 1 while i >= 0 and not self.calevents[ev_ids[i]]['tags']: i -= 1 if i >= 0: tag = self.calevents[ev_ids[i]]['tags'][-1] label.configure(style='tag_%s.%s.TLabel' % (tag, self._style_prefixe)) # modified lines: text = '%s\n' % day_number + '\n'.join([self.calevents[ev]['text'] for ev in ev_ids]) label.configure(text=text) else: label.configure(text='', style=style) def _display_days_with_othermonthdays(self): year, month = self._date.year, self._date.month cal = self._cal.monthdatescalendar(year, month) next_m = month + 1 y = year if next_m == 13: next_m = 1 y += 1 if len(cal) < 6: if cal[-1][-1].month == month: i = 0 else: i = 1 cal.append(self._cal.monthdatescalendar(y, next_m)[i]) if len(cal) < 6: cal.append(self._cal.monthdatescalendar(y, next_m)[i + 1]) week_days = {i: 'normal' for i in range(7)} # style names depending on the type of day week_days[self['weekenddays'][0] - 1] = 'we' week_days[self['weekenddays'][1] - 1] = 'we' prev_m = (month - 2) % 12 + 1 months = {month: '.%s.TLabel' % self._style_prefixe, next_m: '_om.%s.TLabel' % self._style_prefixe, prev_m: '_om.%s.TLabel' % self._style_prefixe} week_nb = cal[0][1].isocalendar()[1] modulo = max(week_nb, 52) for i_week in range(6): self._week_nbs[i_week].configure(text=str((week_nb + i_week - 1) % modulo + 1)) for i_day in range(7): style = week_days[i_day] + months[cal[i_week][i_day].month] label = self._calendar[i_week][i_day] label.state(['!disabled']) txt = str(cal[i_week][i_day].day) label.configure(text=txt, style=style) if cal[i_week][i_day] in self._calevent_dates: date = cal[i_week][i_day] ev_ids = self._calevent_dates[date] i = len(ev_ids) - 1 while i >= 0 and not self.calevents[ev_ids[i]]['tags']: i -= 1 if i >= 0: tag = self.calevents[ev_ids[i]]['tags'][-1] label.configure(style='tag_%s.%s.TLabel' % (tag, self._style_prefixe)) # modified lines: text = '%s\n' % date.day + '\n'.join([self.calevents[ev]['text'] for ev in ev_ids]) label.configure(text=text) def _show_event(self, date): """Display events on date if visible.""" w, d = self._get_day_coords(date) if w is not None: label = self._calendar[w][d] if not label.cget('text'): # this is an other month's day and showothermonth is False return ev_ids = self._calevent_dates[date] i = len(ev_ids) - 1 while i >= 0 and not self.calevents[ev_ids[i]]['tags']: i -= 1 if i >= 0: tag = self.calevents[ev_ids[i]]['tags'][-1] label.configure(style='tag_%s.%s.TLabel' % (tag, self._style_prefixe)) # modified lines: text = '%s\n' % date.day + '\n'.join([self.calevents[ev]['text'] for ev in ev_ids]) label.configure(text=text)if __name__ == '__main__': import tkinter as tk root = tk.Tk() root.geometry("800x500") agenda = Agenda(root, selectmode='none') date = agenda.datetime.today() + agenda.timedelta(days=2) agenda.calevent_create(date, 'Hello World', 'message') agenda.calevent_create(date, 'Reminder 2', 'reminder') agenda.calevent_create(date + agenda.timedelta(days=-7), 'Reminder 1', 'reminder') agenda.calevent_create(date + agenda.timedelta(days=3), 'Message', 'message') agenda.calevent_create(date + agenda.timedelta(days=3), 'Another message', 'message') agenda.tag_config('reminder', background='red', foreground='yellow') agenda.pack(fill="both", expand=True) root.mainloop()