При изучении Tkinter столкнулся с досадной проблемой. Если собрать программу в exe с помощью PyInstaller, то в полях ввода текста вместо кириллицы вводится абракадабра в стиле "???????????", хотя текст, заданный из самой программы (Label, Button и т.п.), выглядит нормально. Причём исходный py-скрипт работает адекватно.
Перерыв кучу интернет-ресурсов, испробовал несколько приёмов решения проблемы с кодировкой, но ни один из них не сработал. Так как мой проект уже разросся до солидных размеров, а менять Tkinter на другой GUI мне очень не хотелось, я принялся за поиск решения.
В результате многочисленных проб и ошибок родился этот довольно грязный хак, который, однако, вполне справляется с поставленной задачей.
#!/usr/bin/python
# -*- coding: utf-8 -*-
from Tkinter import *
class FormatStringVar(StringVar):
def __init__(self, root):
StringVar.__init__(self)
self.root = root
# Устанавливаем callback-функцию. Она будет выполняться
# каждый раз при изменении значения переменной
self.trace_variable("w", self.callback)
# CHARMAP
# Составляем словарь необходимых символов
_CHR = u"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя"
self._CHARMAP = dict()
# от 'А' до 'Я' (192-223) и от 'а' до 'я' (224-255)
i = 192
for c in _CHR:
self._CHARMAP[i] = c
i += 1
# Остальные символы, включая украинские
self._CHARMAP[168] = u"Ё"
self._CHARMAP[184] = u"ё"
self._CHARMAP[178] = u"І"
self._CHARMAP[179] = u"і"
self._CHARMAP[175] = u"Ї"
self._CHARMAP[191] = u"ї"
self._CHARMAP[170] = u"Є"
self._CHARMAP[186] = u"є"
self._CHARMAP[165] = u"Ґ"
self._CHARMAP[180] = u"ґ"
# callback-функция
def callback(self, name, index, mode):
# получаем значение переменной
old = self.root.globalgetvar(name)
new = u""
# для каждого символа в строке
for i in old:
# если символ входит в словарь
if ord(i[-1]) in self._CHARMAP:
# заменяем на правильное значение
new += self._CHARMAP[ord(i[-1])]
# если символа нет в словаре
else: # оставляем символ
new += i
# записываем результат обратно в переменную
self.root.globalsetvar(name, new)
# инициализируем Tkinter
root = Tk()
# устанавливаем в Tkinter кодировку UTF-8
root.tk.call('encoding', 'system', 'utf-8')
mainframe = Frame(root)
mainframe.pack()
# Инициализируем нашу переменную
entry_var = FormatStringVar(root)
# Привязываем переменную к полю ввода Entry
entry = Entry(mainframe, textvariable=entry_var)
entry.pack()
# Поехали!
root.mainloop()
Не знаю может у кого-то что-то иполучилось так. Но я пошел другим путем.
Не буду долго рассказывать… просто при упаковке pyinstaller не добавляет папку C:\Python26\tcl\tcl8.5\encoding. это можно заметить если запустить прогу и залесть в C:\temp\_MEI7202\_MEI\tcl8.5, там нет папки encoding. Я просто кинул туда папку encoding и прога сразу подхватира кодеки. Дальше я подумал что гдето эксклюдится эта папка и нашел что это происходит в скрипте Build.py pyinstaller-a там есть такие строки
Не буду долго рассказывать… просто при упаковке pyinstaller не добавляет папку C:\Python26\tcl\tcl8.5\encoding. это можно заметить если запустить прогу и залесть в C:\temp\_MEI7202\_MEI\tcl8.5, там нет папки encoding. Я просто кинул туда папку encoding и прога сразу подхватира кодеки. Дальше я подумал что гдето эксклюдится эта папка и нашел что это происходит в скрипте Build.py pyinstaller-a там есть такие строки
я их заменил на
и все… папка encoding пакуется — кирилица вводится.
Но все равно спасибо за этот класс некоторые вещи я не знал… видимо по тому что не надо было :)