charm ah
charm ah

Reputation: 93

TkCalendar: Trying to display multiple DateEntries on screen simultaneously leads to TclError

I am currently working on a school project that records employee information for a company and generates a rota based on factors such as employee availability, job role, etc.

In order to record employee holidays, I am using the module TkCalendar, which has its own Calendar and DateEntry objects which can be used to display GUI calendar information. However, I have recently changed computer and a segment of code which was used to allow users to add in holidays does no longer work; it appears that, when trying to create the second DateEntry object, TkCalendar raises an error which seems to imply that the options I have passed into the second object are invalid. This is confusing, as the first DateEntry object seems to be generated fine. Below is a test case example of the issue I am having:

from tkinter import *
from tkcalendar import DateEntry

class TestApp:
    def __init__(self, root):
        self.root = root
        self.window = Frame(self.root)
        self.window.pack()

        self.label, self.calendar = [], []
        self.font = ('Impact Bold', 13, 'bold')

        labels = ['Select start date:', 'Select end date:']
        for i in range(2):
            self.label.append(Label(self.window, text=labels[i], font=self.font))
            self.label[-1].grid(row=i+1, column=0)

            self.calendar.append(DateEntry(self.window, font=self.font, locale='en_GB', width=15))
            self.calendar[-1].grid(row=i+1, column=3)


if __name__ == '__main__':
    root = Tk()
    app = TestApp(root)
    root.mainloop()

This generates the following exceptions:

Traceback (most recent call last):
  File "C:\Users\xav\Documents\Python files\TkCalendar DateEntry test case.py", line 24, in <module>
    app = TestApp(root)
  File "C:\Users\xav\Documents\Python files\TkCalendar DateEntry test case.py", line 18, in __init__
    self.calendar.append(DateEntry(self.window, font=self.font, locale='en_GB', width=15))
  File "C:\Users\xav\AppData\Local\Programs\Python\Python38\lib\site-packages\tkcalendar\dateentry.py", line 105, in __init__
    self._setup_style()
  File "C:\Users\xav\AppData\Local\Programs\Python\Python38\lib\site-packages\tkcalendar\dateentry.py", line 160, in _setup_style
    self.style.map('DateEntry', **maps)
  File "C:\Users\xav\AppData\Local\Programs\Python\Python38\lib\tkinter\ttk.py", line 403, in map
    self.tk.call(self._name, "map", style, *_format_mapdict(kw)),
_tkinter.TclError: Invalid state name r

The TkCalendar documentation can be found here. Thanks for any help in advance!

Upvotes: 1

Views: 657

Answers (1)

j_4321
j_4321

Reputation: 16179

This issue have been reported in tkcalendar https://github.com/j4321/tkcalendar/issues/61 and seems to come from a change in python https://bugs.python.org/issue38661. As far as I know it happens only in Windows (I use tkcalendar with python 3.8 in linux without issues). The issue is that the style map returned by self.style.map('TCombobox') is not a valid style map, while it used to be and should be according to the ttk.Style.map() docstring.

Below is a temporary fix while waiting for a solution for the python issue. The idea is to override the method of the DateEntry which triggers the error and manually provide the correct style map to the DateEntry (see code below).

from tkcalendar import DateEntry as TkcDateEntry
import tkinter as tk

class DateEntry(TkcDateEntry):
    def _setup_style(self, event=None):
        # override problematic method to implement fix
        self.style.layout('DateEntry', self.style.layout('TCombobox'))
        self.update_idletasks()
        conf = self.style.configure('TCombobox')
        if conf:
            self.style.configure('DateEntry', **conf)
        # The issue comes from the line below:
        maps = self.style.map('TCombobox')
        if maps:
            try:
                self.style.map('DateEntry', **maps)
            except tk.TclError:
                # temporary fix to issue #61: manually insert correct map
                maps = {'focusfill': [('readonly', 'focus', 'SystemHighlight')],
                        'foreground': [('disabled', 'SystemGrayText'),
                                       ('readonly', 'focus', 'SystemHighlightText')],
                        'selectforeground': [('!focus', 'SystemWindowText')],
                        'selectbackground': [('!focus', 'SystemWindow')]}
                self.style.map('DateEntry', **maps)
        try:
            self.after_cancel(self._determine_downarrow_name_after_id)
        except ValueError:
            # nothing to cancel
            pass
        self._determine_downarrow_name_after_id = self.after(10, self._determine_downarrow_name)

Upvotes: 1

Related Questions