TkCalendar:尝试在屏幕上同时显示多个 DateEntries 会导致 TclError
TkCalendar: Trying to display multiple DateEntries on screen simultaneously leads to TclError
我目前正在做一个学校项目,该项目记录公司的员工信息,并根据员工可用性、工作角色等因素生成轮值表。
为了记录员工假期,我使用了模块 TkCalendar,它有自己的 Calendar 和 DateEntry 对象,可用于显示 GUI 日历信息。但是,我最近换了电脑,一段用来让用户添加假期的代码不再起作用了;看起来,当尝试创建第二个 DateEntry 对象时,TkCalendar 引发了一个错误,这似乎暗示我传递给第二个对象的选项无效。这很令人困惑,因为第一个 DateEntry 对象似乎生成得很好。以下是我遇到的问题的测试用例示例:
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()
这会产生以下异常:
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
可以找到 TkCalendar 文档 here。提前感谢您的帮助!
此问题已在 tkcalendar https://github.com/j4321/tkcalendar/issues/61 and seems to come from a change in python https://bugs.python.org/issue38661 中报告。据我所知,它只发生在 Windows 中(我在 linux 中将 tkcalendar 与 python 3.8 一起使用没有问题)。问题是 self.style.map('TCombobox')
返回的样式映射不是有效的样式映射,而它曾经是并且应该根据 ttk.Style.map()
文档字符串。
以下是等待解决 python 问题时的临时修复。这个想法是覆盖触发错误的 DateEntry 方法,并手动向 DateEntry 提供正确的样式映射(请参见下面的代码)。
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)
我目前正在做一个学校项目,该项目记录公司的员工信息,并根据员工可用性、工作角色等因素生成轮值表。
为了记录员工假期,我使用了模块 TkCalendar,它有自己的 Calendar 和 DateEntry 对象,可用于显示 GUI 日历信息。但是,我最近换了电脑,一段用来让用户添加假期的代码不再起作用了;看起来,当尝试创建第二个 DateEntry 对象时,TkCalendar 引发了一个错误,这似乎暗示我传递给第二个对象的选项无效。这很令人困惑,因为第一个 DateEntry 对象似乎生成得很好。以下是我遇到的问题的测试用例示例:
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()
这会产生以下异常:
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
可以找到 TkCalendar 文档 here。提前感谢您的帮助!
此问题已在 tkcalendar https://github.com/j4321/tkcalendar/issues/61 and seems to come from a change in python https://bugs.python.org/issue38661 中报告。据我所知,它只发生在 Windows 中(我在 linux 中将 tkcalendar 与 python 3.8 一起使用没有问题)。问题是 self.style.map('TCombobox')
返回的样式映射不是有效的样式映射,而它曾经是并且应该根据 ttk.Style.map()
文档字符串。
以下是等待解决 python 问题时的临时修复。这个想法是覆盖触发错误的 DateEntry 方法,并手动向 DateEntry 提供正确的样式映射(请参见下面的代码)。
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)