Краткий обзор Tkinter

Это краткая справочная информация к Tkinter. Ее следует рассматривать как дополнение, а не альтернативу основному справочному материалу. Глубина изложения варьируется от самого простого уровня до изощренных приемов. Документ содержит информацию, которую мне самому было трудно найти.

Элементарное приложение Tk

import Tkinter
root = Tkinter.Tk()
# опишите свой интерфейс, затем запустите приложение с помощью команды:
root.mainloop()

Стандартные элементы управления

Простые элементы управления: Toplevel, Frame, Button, Checkbutton, Entry, Label, Listbox, OptionMenu, Photoimage, Radiobutton, Scale.

Сложные элементы управления: Canvas, Text. Они могут содержать внутри себя помеченные тегами элементы, которые ведут себя подобно объектам.

Трудные для использования: Menu, Menubutton, Scrollbar.

Переменные Tk: StringVar, IntVar, DoubleVar, BooleanVar. Это своего рода контейнеры данных (контейнер - объект или приложение, содержащие другие объекты.- Прим. пер.). Они необходимы для некоторых элементов управления и взаимодействуют со многими другими, обеспечивая легкий доступ к их содержимому, а также могут инициировать обратные вызовы при изменении своих данных.

Дополнительные модули (не загружаемые командой "import Tkinter")

tkFont определяет класс Font для параметров шрифта и присвоения имен шрифтов. Если объект Font связать с шрифтом элемента управления, тогда изменение объекта Font будет автоматически приводить к соответствующим изменениям данного элемента управления.

FileDialog определяет FileDialog, LoadFileDialog, SaveFileDialog. Пример:

fdlg = FileDialog.LoadFileDialog(root, title="Выберите файл")
fname = fdlg.go() # необязательные аргументы:
    dir_or_file=os.curdir, pattern="*", default="", key=None)
if fname == None: # отмена пользователем

tkColorChooser определяет функцию askcolor(initialcolor), которая возвращает выбранный пользователем цвет.

tkSimpleDialog определяет askinteger(title, prompt, initialvalue, minvalue, maxvalue), askfloat и askstring.

Просмотрите исходный код файлов с расширением .py в каталоге .../Lib/lib-tk. Там есть и другие модули, а также примеры использования.

Диспетчеры компоновки

Упаковщик (диспетчер Pack)

pack(side="top/right/bottom/left", expand=0/1, anchor="n/nw/w...", fill="x/y/both")

  • По умолчанию элементы управления внутри доступного пространства размещаются по центру; изменить способ расположения можно при помощи опции привязки (anchor).
  • По умолчанию элементы управления не развертываются так, чтобы заполнить все доступное пространство; изменить способ развертывания можно с помощью опций expand и fill.

Диспетчер сетки (Grid)

grid(row, column, rowspan=?, columnspan=?, sticky="news", ipadx=?, ipady=?, padx=?, pady=?)

columnconfigure(row, weight=?, minsize=?, pad=?)

columnconfigure(column, weight=?, minsize=?, pad=?

  • Каждая строка и каждый столбец сжимаются так, чтобы соответствовать наименьшему элементу в данной строке или данном столбце.
  • По умолчанию элементы управления внутри ячейки выравниваются по центру; для изменения способа выравнивания воспользуйтесь опцией sticky.
  • По умолчанию строки и столбцы не расширяются при изменении размеров окна пользователем; изменить такое поведение возможно с помощью команд rowconfigure и columnconfigure, присвоив ненулевые значения параметрам weight.
  • Rowconfigure и columnconfigure также полезны при разрешении часто встречающейся проблемы: когда объект занимает несколько строк или столбцов, может произойти увеличение размеров этих строк или столбцов. Положим, у вас есть два столбца шириной 20 и 30 пикселей, соответственно. Кроме того, вам нужно обработать с помощью диспетчера сетки "широкий элемент управления" шириной 100 пикселей, не расширяя уже имеющиеся столбцы. Если просто разместить новый объект с помощью диспетчера grid, заняв два столбца, ширина столбцов увеличится, так чтобы в сумме получилось 100 пикселей (каждый из них получит еще по 25 пикселей, ширина столбцов станет в итоге 45 и 55 пикселей, соответственно). Размещение широкого объекта в большем числе столбцов сетки смягчает проблему (за счет распределения "лишних" пикселей между столбцами), но не разрешает ее окончательно. Решение заключается в распространении широкого элемента управления по крайней мере еще на один столбец, после чего с помощью columnconfigure дополнительному столбцу присваивается вес (weight), равный 1.

События и обратные вызовы

События

События описываются с помощью строк вида: "<modifiers-type-qualifier>" ("модификаторы-спецификатор типа").

Типы событий:

  • мышь (модификаторы B1 и т.д. определяют, о какой кнопке мыши идет речь):
    • ButtonPress (может быть сокращено до Button, модификатор Double)
    • ButtonRelease
    • Enter
    • Leave
    • Motion
  • клавиатура (такие модификаторы, как Control, Shift, Meta ...)
    • KeyPress (может быть сокращено до Key)
    • KeyRelease
  • окно (в языке Tk любой элемент управления является окном):
    • Configure (окно изменяет свой размер, перемещается и т.д.)
    • Expose
    • FocusIn
    • FocusOut
    • Map
    • Unmap

Предупреждение: то, какие именно события видит тот или иной элемент управления, зависит от платформы.

Определители для KeyPress и KeyRelease - это символы клавиатуры (keysyms). Буквы и цифры используются как есть, но знаки пунктуации и все остальные клавиши требуют особых, чувствительных к регистру имен, как-то: comma (запятая), period (точка), dollar (доллар), asciicircum (^), numbersign (#), exclam (восклицательный знак), Return, Escape, BackSpace, Tab, Up (вверх), Down (вниз), Left (влево), Right (вправо)... В сомнительных случаях запустите интерактивный тест, наподобие примера, приведенного ниже.

Для того чтобы при наступлении некоторого события происходило обращение к обратному вызову, создайте соответствующую привязку (bind):
widget.bind(event, callback)

  • Обратный вызов получает в точности один-единственный аргумент: заданное событие.
  • Данное событие содержит следующие атрибуты (неполный список):
    • keysym: символ клавиши, как описано выше (события KeyPress и KeyRelease)
    • height (высота), width (ширина) (событие Configure)
    • serial: порядковый номер события (все события)
    • type: число, обозначающее тип события (все события)
    • time: время события (все события)
    • widget: элемент управления, принимающий данное событие (все события)
    • x, y: положение курсора мыши по отношению к данному элементу управления (события, связанные с мышью, и, возможно, все события)
    • x_root, y_root: положение курсора мыши по отношению к корневому окну (события, связанные с мышью, и, возможно, все события)
  • Чтобы заблокировать событие, достаточно вернуть строку "break" из вашего обратного вызова; это может пригодиться, когда нужно "подавить" принятое по умолчанию поведение элемента управления.
  • Существуют и другие типы/уровни связывания, например можно связать событие со всеми экземплярами определенного класса (например, все клавиши - Buttons). Дополнительную информацию можно найти во Введении в Tkinter.

Ниже приводится пример, в котором при нажатии любой кнопки клавиатуры выводится соответствующий символ клавиши:

        #!/usr/local/bin/Python
        """Отображает символ клавиши (keysym) 
        для каждого события KeyPress (нажатия клавиатуры)."""
        import Tkinter
        
        root = Tkinter.Tk()
        root.title("Регистратор символов клавиатуры")
        
        def reportEvent(event):
                print 'keysym=%s, keysym_num=%s' % (event.keysym, event.keysym_num)
        
        text  = Tkinter.Text(root, width=20, height=5, highlightthickness=2)
        
        text.bind('<KeyPress>', reportEvent)
        
        text.pack(expand=1, fill="both")
        text.focus_set()
        root.mainloop()

Обработчик протокола WM_DELETE_WINDOW

Обратный вызов события Destroy (уничтожить) запускается слишком поздно, чтобы с его помощью можно было очистить элемент управления или предотвратить уничтожение окна. Сделать что-либо из перечисленного можно с помощью обработчика протокола WM_DELETE_WINDOW. (Но если удаление требуется при выходе из приложения, лучше воспользоваться стандартной библиотекой python "atexit"; это проще!). Этот протокол позволяет производить действия, отличные от поведения, принятого по умолчанию. Если вам действительно нужно уничтожить окно, сделайте это сами. Данный обратный вызов не получает никаких аргументов.

toplevel.protocol("WM_DELETE_WINDOW", callback)

Существуют два других протокола: WM_SAVE_YOURSELF и WM_TAKE_FOCUS. Не вполне ясно, для чего они нужны.

Команды элементов управления

Элементы управления, такие как Button (кнопка), имеют параметр "command" ("команда"). В данном случае обратный вызов не получает аргументов на входе. Это самый лучший путь запустить обратный вызов при нажатии кнопки Button, поскольку не существует другого события, связанного с мышью, делающего ту же самую работу. Конечно жаль, что "командные" (относящиеся к параметру "command".- Прим. пер.) обратные вызовы не передают функции обратного вызова никакой информации, но ситуацию легко исправить с помощью т.н. посредника обратного вызова (Callback Shim).

Переменные слежения

Для того чтобы при изменении переменной Tk запускался обратный вызов, можно воспользоваться методом trace_variable:
traceName = tkvar.trace_variable(mode, callback)

  • Параметр mode (режим) может иметь одно из трех значений: "r", "w" или "u" (чтение, запись или обновление)
  • Обратный вызов получает 3 аргумента: varName (имя переменной Tk), index (всегда ''?), mode (режим)
  • Обратный вызов callback может изменить содержимое переменной, не обращаясь к другому обратному вызову
  • Чтобы получить или изменить значение переменной произвольного элемента управления (anywdg) по ее имени, воспользуйтесь выражениями вида anywdg.getvar(varName), anywdg.setvar(varName, value)
  • Удалить обратный вызов можно с помощью выражения tkvar.trace_delete(traceName)
  • Дополнительную информацию можно найти в документе Фольклор Tkinter.

After: синхронизированные события и анимация

Чтобы запустить обратный вызов с определенной задержкой, например для анимации, воспользуйтесь методом after (после):
widget.after(timems, callback, arg1, arg2...)

  • arg1, arg2... представляют собой нулевое или любое другое число дополнительных аргументов
  • Обратный вызов callback получает только эти дополнительные аргументы (если они есть)
  • Обратный вызов callback вызывается один раз при каждом обращении к after.

Обработчики файлов/сокетов

Вопрос в том, как организовать взаимодействие посредством сокета (особенно, как считывать информацию), не используя цикл событий и избегая неэффективных решений. Есть несколько вариантов:

Обработчики файлов

Обработчик файлов обращается к обратному вызову, когда в файле либо сокете есть данные для чтения или записи. Обработчики файлов просты и хорошо интегрированы в Tkinter. К сожалению, они не работают под Windows (по крайней мере с версией Python 2.3.4 и Windows XP). Но если ваша программа будет запускаться только на unix и/или MacOS X, то из-за простоты применения предпочтение следует отдать именно им.

wdg.tk.createfilehandler(file_or_socket, mask, callback)
где wdg - произвольный элемент управления Tkinter (если под рукой ничего нет, создайте для этих целей новый фрейм (frame)).

  • Mask (шаблон): произвольная комбинация Tkinter.READABLE, Tkinter.WRITABLE, Tkinter.EXCEPTION, соединенных оператором OR (ИЛИ)
  • Обратный вызов (callback) получает в точности два аргумента: file_or_socket (файл_или_сокет), mask (шаблон)
  • Любой файл может иметь только одного обработчика. Еще один вызов createfilehandler просто заменит старого обработчика на нового.
  • Чтобы окончательно удалить обработчик, вызовите функцию deletefilehandler(file_or_socket)
  • Для временного удаления обработчика вызовите createfilehandler(file_or_socket, None). Это лучше, чем удалить обработчика файлов, а потом воссоздавать его.
  • 6 мая 2003 г. я изменил обозначения. В версиях Python 2.2.x можно было писать "tkinter", но это перестало срабатывать с Python 2.3 (по крайней мере, если tcl собран с использованием нитей (threads)). Новый способ работает с Python 2.3 и Python 2.2.2, а также, вероятно, и с некоторыми более ранними версиями.

Сокеты Tcl

Сокеты Tcl полностью кроссплатформенны, но пользоваться ими немного труднее, поскольку приходится самостоятельно писать tcl-код. Тем не менее, это совсем не сложно, а затраченные усилия с лихвой окупаются тем, что вы получаете полностью переносимый код. Как пример использования tcl-сокетов можно загрузить мой пакет RO package и просмотреть RO.Comm.TkSocket. См. также следующее сообщение Мэтью Синсера (Matthew Cincera), которое я взял в качестве отправной точки (попутно приношу благодарность Стефану Беланду (Stephane Beland), посоветовавшему мне эту ссылку).

Twisted Framework

Twisted Framework - это свободная кроссплатформенная сетевая библиотека, работающая с несколькими разными инструментариями GUI (фактически, для своей работы она и не нуждается в каком-либо GUI-инструментарии). У нее очень хорошая репутация. До сих пор мне не приходилось пользоваться этой библиотекой, но, скорее всего, когда-нибудь я на нее перейду.

Посредники обратного вызова (перенос функции)

Так получается, что мне часто бывает нужно передать в функцию обратного вызова больше данных, чем это предусмотрено. К примеру, элемент управления Button (кнопка) не передает никаких аргументов через свой "командный" (имеется ввиду параметр command) обратный вызов, но может оказаться эффективнее использовать одну функцию обратного вызова для управления несколькими кнопками; в этом случае мне необходимо знать, какая именно кнопка была нажата.

Реализовать это возможно, определив функцию обратного вызова непосредственно перед ее пересылкой в элемент управления и включив в нее всю дополнительную информацию, которая вам нужна. К сожалению, Python, как и большинство других языков, не поддерживает на достаточно хорошем уровне смешение раннего связывания (информация, известная при определении функции) и позднего связывания (информация, известная при вызове функции). Я считаю, что самым простым и ясным будет следующее решение:

  • Записать функцию обратного вызова так, чтобы все нужные данные были ее аргументами.
  • С помощью класса посредника обратного вызова создать вызываемый объект, в котором хранится моя функция и дополнительные аргументы и который при вызове будет делать все так, как надо. Другими словами, он вызывает мою функцию с сохраненными данными плюс данные, предоставляемые вызывающей процедурой.

Надеюсь, что приведенный далее пример прояснит сказанное.

Посредник обратного вызова, которым я пользуюсь, называется RO.Alg.GenericCallback. Он входит в мой пакет RO package. Упрощенная версия посредника, не умеющая работать с аргументами в виде ключевых слов, описана в примере, приведенном ниже по тексту. Весь код посредника основан на python-рецепте Скотта Дэвида Дэниэлса (Scott David Daniels), который называет этот прием "переносом функции" ("currying a function"); последний термин, возможно, более распространен, чем "посредник обратного вызова" ("callback shim").

        #!/usr/local/bin/Python
        """Пример, демонстрирующий применение посредника обратного вызова"""
        import Tkinter
        
        def doButton(buttonName):
               """Желаемый обратный вызов. Мне потребуется посредник
                обратного вызова, поскольку через параметр command элемента
                Button (кнопка) обратные вызовы никаких аргументов получить
                не могут."""
                print buttonName, "pressed"
        
        class SimpleCallback:
                """Создается посредник обратного вызова, основанный на коде,
                 предложенном Скоттом Дэвидом Дэниелсом (Scott David Daniels),
                 который может работать и с ключевыми словами-аргументами."""
        
                def __init__(self, callback, *firstArgs):
                        self.__callback = callback
                        self.__firstArgs = firstArgs
        
                def __call__(self, *args):
                        return self.__callback (*(self.__firstArgs + args))
        
        root = Tkinter.Tk()
        
        buttonNames = ("Button 1", "Button 2", "Button 3")
        
        for name in buttonNames:
                callback = SimpleCallback(doButton, name)
                Tkinter.Button(root, text=name, command=callback).pack()
        
        root.mainloop()

Индексирование

Элемент управления Text (текст)

  • "line.col" line = номер строки, нумерация начинается с 1 (!); col = столбец # нумерация начинается с 0
  • "current" (текущий) символ под курсором мыши
  • "insert" (вставить) символ после курсора
  • "end" (конец) - сразу после конца
  • "@x,y" - символ в определенном месте экрана
  • "tag.first" ("тег.первый"), "tag.last" ("тег.последний") - первый символ, сразу после последнего символа с заданным тегом

Эти обозначения могут быть модифицированы путем добавления следующих строк:

  • " +/- n chars" (+/- n символов)
  • " +/- n lines" (+/- n строк)
  • " linestart" (начало строки)
  • " linend" (конец строки)
  • " wordstart" (начало слова)
  • " wordend" (конец слова)

Например, "1.0 lineend" означает ссылку на конец первой строки.

Элемент управления Entry (ввод)

  • целые числа, начиная с 0 (или строковые выражения)
  • "end", "insert", "@x,y" (см. выше раздел, посвященный элементу управления Text)
  • "anchor" (точка привязки выделения), "sel.first" (первое выделение), "sel.last" (последнее выделение)

Получение информации от элементов управления

Есть несколько путей, как получить информацию о настройке элемента управления:

  • Трактовать его как словарь: aWidget["text"]. (Замечание: это относится как к заданию, так и к получению данных.)
  • Использовать метод cget: aWidget.cget("text").
  • Вы можете вызвать словарь всех параметров настройки, применив метод configure без аргументов: aWidget.configure().

Во всех случаях каждый параметр настройки возвращается в виде строки. Это может стать главным источником головной боли. К примеру, булевы значения будут "0" или "1" (оба из которых логически истинны в Python). Проблема становится еще хуже, когда речь заходит об извлечении обычных объектов Tkinter, таких как переменные Tk или графические элементы управления. Следующий пример иллюстрирует эту проблему (хотя и в такой простой ситуации, когда приходится иметь дело лишь с оригинальными объектами Tk); ниже обсуждаются ее возможные решения:

import Tkinter
root = Tkinter.Tk()
aVar = Tkinter.StringVar()
aLabel = Tkinter.Label(textvar = aVar)
aLabel["textvar"]
  'PY_VAR0'
root.setvar(aLabel["textvar"], "foo")
aLabel.getvar(aLabel["textvar"])
  'foo'
str(aLabel)
  '.8252000'
root.nametowidget(str(aLabel))
  <Tkinter.Label instance at 0x7dea60>
aLabel.master
  <Tkinter.Label instance at 0x7dea60>
root.master
  None
        

Выбор подхода зависит от того, что вы хотите извлечь:

  • Переменную, такую как StringVar. Если имя переменной известно, ее значение можно считать или задать с помощью функций getvar(имя_переменной) и setvar(имя_переменной, новое_значение). Можно также создать переменную Tkinter, которая будет в точности дублировать оригинал, но это очень некрасивое решение. Вместо этого рекомендуется использовать getvar и setvar (или использовать первоначальную переменную Tkinter). Если все-таки по какой-то причине дублирование необходимо, сначала создайте новую переменную Tkinter, например v = Tkinter.StringVar(), а затем задайте ее свойство _name: v._name = name_of_variable. Проблема в том, что создается новая переменная Tk, которая никогда не будет использоваться, а базируется вся эта методика на недокументированных свойствах переменных Tkinter. (У меня даже нет полной уверенности, что это безопасно, из-за возможных проблем, связанных со сборкой мусора в памяти.)
  • Отображаемый на экране элемент управления (например, Button). Если имя элемента управления известно, его можно преобразовать в объект Tkinter с помощью метода nametowidget(имя_элемента). Также возможно извлечь и родительский элемент управления с помощью выражения wdg.master (который вместо названия элемента управления возвращает соответствующий элемент управления Tkinter).
  • Объект tkFont.Font (который соответствует "именованному шрифту" Tk). Если создать объект tkFont.Font и задавать с его помощью шрифт для элемента управления или класса элементов управления, то, воздействуя на объект tkFont.Font, можно изменять шрифт элемента/элементов управления. Это очень полезно для процедур задания предпочтений пользователем и т.п. Ну, а если, предположим, вы не хотите все время держать под рукой данный объект tkFont.Font? Существует возможность создать новый, задавая элемент управления wdg, который использует данный именованный шрифт. Но этот вариант настолько некрасив, что обычно предпочитают работать с первоначальным объектом tkFont.Font. Сначала создайте новый объект tkFont.Font f = tkFont.Font(), затем присвойте ему соответствующее имя f.name = wdg["font"]. Если попробовать более прямой путь: f = tkFont.Font(name = wdg["font"]), появится сообщение об ошибке _tkinter.TclError: "named font ... already exists" - "именованный шрифт ... уже существует" (по крайней мере с версией Python 2.3b1).
  • Замечание: getvar, setvar и nametowidget могут обращаться к любому элементу управления Tkinter, оказавшемуся под рукой, например любой_элемент.getvar(имя_переменной).

Советы

Это перечень ошибок, часто встречающихся при программировании на python и Tkinter, а также способы их избежания.

  • Функции обратного вызова должны определяться без круглых скобок и, следовательно, без аргументов. Если поставить скобки, Python вызовет эту функцию только один раз (при настройке GUI), а возвращаемое значение будет использоваться как функция обратного вызова. Это очень распространенная ошибка начинающих. Так происходит, в частности, когда пользователи хотят задать аргументы вместе с функцией обратного вызова. Удачный вариант решения этой задачи - использование посредников обратного вызова.
  • Никогда не пытайтесь обрабатывать элементы управления диспетчерами компоновки pack и grid в одном родительском элементе. Это приведет к бесконечному циклу! Если ваше приложение зависает во время прорисовки окна, это первое, что нужно проверить. Найти такую ошибку непросто. В случае затруднений внимательно просмотрите родительские элементы у каждого элемента управления; может быть, задан не тот родительский элемент или, возможно, он вообще не указан (тогда по умолчанию родительским элементом будет root).
  • При сложной геометрии для группировки элементов управления пользуйтесь фреймами; обычно это проще и безопаснее, чем изощряться с диспетчером компоновки pack или grid. Но будьте очень внимательны, правильно задавайте родительский элемент для каждого элемента управления, или возникнет путаница, даже возможен конфликт между диспетчерами grid и pack (бесконечный цикл).
  • Линейку прокрутки (scrollbar) нужно упаковать до того, как этот элемент управления начнет прокручиваться. Тогда, если окно сожмется до такой степени, что не сможет показывать все свое содержимое, линейка прокрутки останется видимой.
  • Мои изображения или иконки пропадают с элементов управления Tk; что случилось? Экземпляры PhotoImage не обычны в том отношении, что требуют явной ссылки на себя. Не достаточно просто поместить изображение на элемент управления Tkinter (это не приводит к увеличению числа ссылок на это изображение). Обычные решения в этом случае - рассматривать изображение как новый атрибут элемента управления Tkinter, например mywdg._imageref = myimage, или связать изображение с какой-либо глобальной переменной.
  • Все обращения Tkinter должны осуществляться из основного потока-нити (или, точнее, из потока под названием mainloop). Нарушение этого правила может привести к таким тяжелым и необъяснимым проблемам, как зависание системы или "падение" ядра (core dump). Да, в результате совмещение многопоточности с Tkinter становится крайне сложным. Единственная полностью безопасная методика, которую я сумел найти,- это механизм опроса (polling) The only fully safe technique I have found is polling (например использовать after из основного цикла (main loop), чтобы запросить threading Queue, который записывает ваш поток). Высказывалось мнение, что использование потоками event_create для коммуникации с главным потоком является безопасным, но проверка показала, что этот способ не безопасен.
  • Никогда не используйте изменяющиеся объекты (такие как список, словарь или просто что-либо за исключением числа, строки, кортежа или None) в роли значения аргумента, принятого по умолчанию. Тогда это значение по умолчанию легко может быть изменено (если ваша функция изменяет аргумент внутри себя). Так def foo(alist=[]):... - это мина, ждущая своего часа. Избежать подобных проблем можно, взяв в качестве значения по умолчанию None, провести внутреннюю проверку для None и заменить его на [] (или {} или что-либо другое).

Ресурсы

  • Введение в Tkinter Фредрика Лундха (Fredrik Lundh) - это отличная стартовая точка. К сожалению, оно не закончено и, по-видимому, в таком виде и останется.
  • В книге "Python in a Nutshell" ("Python в двух словах") Алекса Мартелли (Alex Martelli) есть краткое, но добротное введение в Tkinter. Вообще, это очень хорошая справочная книга по Python; на мой взгляд, у каждого серьезного программиста, работающего на Python, должна быть "Python in a Nutshell" и/или "Python Essential Reference" ("Справочное руководство по Python") Дэвида Бизли (David Beazley).
  • Фольклор Tkinter содержит сведения о Tkinter, которые мне было трудно найти.
  • "Практическое программирование на Tcl и Tk", книга, написанная Брентом Уэлшом (Brent Welch). Это великолепный справочник для работы с Tk. Tkinter очень похож на Tk, а серьезная справочная информация по Tkinter встречается столь редко, что эту книгу можно считать незаменимой. Замечание: я не знаком со всеми существующими книгами по Tk. Просто в свое время в руки попалась именно книга Уэлша, и она произвела очень хорошее впечатление. [Перевод на русский язык: Уэлш Б.Б., Джонс К., Хоббс Д. Практическое программирование на Tcl и Tk.- М.: Издательский дом "Вильямс", 2004.- 1136 с.- Прим. пер.]
  • Python and Tkinter Programming" ("Python и программирование на Tkinter") Джона Грейсона (John Grayson) - в настоящее время единственная книга, полностью посвященная нашей теме. Но имейте в виду, что в ней большое внимание уделяется пакету Pmw в ущерб Tkinter. Также кое-какая важная информация в ней отсутствует или ее трудно найти. Но если вам приходится много работать с Tk, эта книга определенно необходима. Я часто обращаюсь к ее справочному разделу в конце. Книгу Грейсона предпочтительно использовать в сочетании с хорошим справочником по Tk, таким как "Практическое программирование на Tcl и Tk" (упомянутым выше).
  • Изучайте код Tkinter и другие файлы в той же директории. Таким образом можно обнаружить немало полезных приемов и разрешить свои проблемы. (Найти каталог Tkinter можно, например, импортировав Tkinter и выполнив команду print Tkinter.__file__).

Автор документа - Рассел Оуэн (Russell Owen). Последнее изменение 2004-10-12 (переписан раздел Обработчик файлов/сокетов, кроме того удалена неработающая ссылка на FAQ - ответы на часто задаваемые вопросы). Настоящий документ можно свободно распространять и использовать, но нельзя продавать.


Перевод на русский язык:

Ф.С.ЗАНЬКО
zanko_philipp@mail.ru

 



Примечание переводчика

Настоящий перевод можно свободно распространять и использовать, но нельзя продавать. При этом текст перевода должен оставаться в неизменном виде.

О замеченных ошибках, неточностях, опечатках просьба сообщать по электронному адресу:

zanko_philipp@mail.ru



Интернет-адрес оригинального документа:
http://www.astro.washington.edu/owen/TkinterSummary.html

Интернет-адрес перевода:
http://www.RussianLutheran.org/