Reputation: 93
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
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