一、背景
tkinter界面中通常会用到日历控件,常用的是tkcalendar,这个包在编译器中使用时一般没什么问题,但是在打包时会出现问题,无论是Pyinstaller还是Nuitka,网上能查到的都是Pyinstaller解决方案,这里写一下Nuitka的解决方案。
二、tkcalendar问题1——Calendar与python自带的calendar冲突
使用这个包通常会有这样一句:
from tkcalendar import Calendar
你会发现这个包编译测试没问题,但打包是就会报错,是因为Calendar这个类(在tkcalendar\calendar_.py下面)会跟python自带的calendar包冲突。
因此要想用,最好对这个类改名,我这里改成CCalendar。
注意有几处相关联的地方需要修改,如果不知道,可以直接编译程序,它会逐个报错说no module named ‘Calendar’,因为他们调用的Calendar类已经被修改为CCalendar类,没有Calendar类了。
(1)在你调用的程序里面修改:
from tkcalendar import CCalendar
(2)去tkcalendar\calendar_.py里面修改:
class CCalendar(ttk.Frame):
"""Calendar widget."""
date = calendar.datetime.date
datetime = calendar.datetime.datetime
timedelta = calendar.datetime.timedelta
strptime = calendar.datetime.datetime.strptime
strftime = calendar.datetime.datetime.strftime
省略下面内容
(3)去tkcalendar\dateentry.py里面修改:
from tkcalendar.calendar_ import CCalendar
# temporary fix for issue #61 and https://bugs.python.org/issue38661
MAPS = {'winnative': {'focusfill': [('readonly', 'focus', 'SystemHighlight')],
'foreground': [('disabled', 'SystemGrayText'),
('readonly', 'focus', 'SystemHighlightText')],
'selectforeground': [('!focus', 'SystemWindowText')],
'fieldbackground': [('readonly', 'SystemButtonFace'),
(4)去tkcalendar_init_.py里面修改:
from tkcalendar.dateentry import DateEntry
from tkcalendar.calendar_ import CCalendar
__version__ = '1.5.0'
三、tkcalendar问题2——babel包相关问题
处理完冲突的问题,在打包后,运行仍会报错,一般提示
FileNotFoundError: [WinError 3] ****************(一堆乱码)
反正意思就是在babel\locale-data没找到一些文件
根据报错,可以看到试运行到babel\localedata.py处的locale_identifiers函数处报错
@lru_cache(maxsize=None)
def locale_identifiers() -> list[str]:
"""Return a list of all locale identifiers for which locale data is
available.
This data is cached after the first invocation.
You can clear the cache by calling `locale_identifiers.cache_clear()`.
.. versionadded:: 0.8.1
:return: a list of locale identifiers (strings)
"""
return [
stem
for stem, extension in
(os.path.splitext(filename) for filename in os.listdir(_dirname))
if extension == '.dat' and stem != 'root'
]
查看函数可以发现,需要有后缀为.dat的文件,实际在locale-data文件夹下是有这些文件的
说明babel这个包没打包成功,把这个包(虚拟环境下一般是在Lib/site-packages/下)放到打包好的.dist文件夹下。
接着又打包,运行仍旧报错,这次说是no module named ‘babel.numbers’,但是babel下面是有numbers.py,试了各种方法,最后直接在起初调用tkcalendar的地方加上一句
from tkcalendar import CCalendar
from babel import numbers
再打包,就能正常运行了。