«Переменные» tkinter и альтернативные способы компоновки форм

peremennye tkinter i alternativnye sposoby komponovki form Экскурсия по tkinter, часть 1

Виджеты Entry (наряду с другими) поддерживают понятие ассоциированной переменной — изменение значения ассоциированной переменной изменяет текст, отображаемый виджетом Entry, а изменение текста в Entry изменяет значение переменной. Однако это не обычные переменные Python. Переменные, связанные с виджетами, являются экземплярами классов переменных в библиотеке tkinter. Эти классы носят названия StringVar, IntVar, DoubleVar и BooleanVar. Выбор того или иного класса зависит от контекста, в котором он должен использоваться. Например, можно связать с полем Entry экземпляр класса StringVar, как показано в примере 8.20.

Пример 8.20. PP4E\Gui\Tour\entry3.py

использует переменные StringVar компоновка по колонкам: вертикальные координаты виджетов могут не совпадать (смотрите entry2)

from tkinter import *

from quitter import Quitter fields = ‘Name’, ‘Job’, ‘Pay’

def fetch(variables):

for variable in variables:

print(‘Input => “%s”’ % variable.get()) # извлечь из переменных

def makeform(root, fields):

form = Frame(root) # создать внешний фрейм

left = Frame(form) # создать две колонки

rite = Frame(form) form.pack(fill=X) left.pack(side=LEFT) rite.pack(side=RIGHT, expand=YES, fill=X) # растягивать по горизонтали

подпись: # растягивать по горизонталиподпись: # связать поле с переменнойvariables = [] for field in fields: lab = Label(left, width=5, text=field) # добавить в колонки ent = Entry(rite) lab.pack(side=TOP)

ent.pack(side=TOP, fill=X) var = StringVar() ent.config(textvariable=var) var.set(‘enter here’) variables.append(var)

return variables

if __name__ == ‘__main__’: root = Tk() vars = makeform(root, fields) Button(root, text=’Fetch’, command=(lambda: fetch(vars))).pack(side=LEFT) Quitter(root).pack(side=RIGHT) root.bind(‘<Return>’, (lambda event: fetch(vars))) root.mainloop()

За исключением того обстоятельства, что поля ввода инициализируются строкой enter here’, этот сценарий создает окно, практически идентичное по внешнему виду и функциям тому, которое создает сценарий entry2 (рис. 8.23 и 8.24). Для наглядности виджеты в окне компонуются другим способом — как фрейм с двумя вложенными фреймами, образующими левую и правую колонки в области формы, — но конечный результат при отображении на экран оказывается тем же самым (на некоторых платформах, по крайней мере: смотрите примечание в конце этого раздела, где описывается, почему компоновка на основе рядов обычно бывает предпочтительнее).

Главное, на что здесь нужно обратить внимание, это использование переменных StringVar. Вместо списка виджетов Entry, из которого извлекаются введенные значения, эта версия хранит список объектов StringVar, которые ассоциируются с виджетами Entry следующим способом:

ent = Entry(rite) var = StringVar() ent.config(textvariable=var) # связать поле с переменной

После того как переменные будут связаны, операции изменения и получения значения переменной

var.set(‘text here’) value = var.get()

действительно будут изменять и получать значение соответствующего поля ввода на экране.[XXXV] Метод get объекта переменной возвращает строку для StringVar, целое число для IntVar и число с плавающей точкой для DoubleVar.

Конечно, как мы уже видели, можно легко изменять и извлекать текст непосредственно из полей Entry, без всяких дополнительных переменных. Зачем же утруждать себя обработкой объектов переменных? Во- первых, исчезает опасность попыток извлечения значений после уничтожения, о чем говорилось в предыдущем разделе. Поскольку объекты StringVar продолжают существовать после уничтожения виджетов Entry, к которым они привязаны, сохраняется возможность извлекать из них значения, когда модального диалога уже давно нет, как показано в примере 8.21.

Пример 8.21. PP4E\Gui\Tour\entry3-modal.py

# значения могут извлекаться из StringVar и после уничтожения виджета

from tkinter import *

from entry3 import makeform, fetch, fields

def show(variables, popup):

popup.destroy() # здесь порядок не имеет значения

fetch(variables) # переменные сохраняются после уничтожения окна

def ask():

popup = Toplevel() # отображение формы в модальном диалоге

vars = makeform(popup, fields)

Button(popup, text=’OK’, command=(lambda: show(vars, popup))).pack()

popup.grab_set()

popup.focus_set()

popup.wait_window() # ждать уничтожения окна

root = Tk()

Button(root, text=’Dialog’, command=ask).pack() root.mainloop()

Эта версия такая же, как исходная (представленная в примере 8.19 и на рис. 8.25), но теперь функция show уничтожает всплывающее окно до извлечения введенных данных из переменных StringVar в списке, созданном функцией makeform. Иными словами, переменные оказываются более надежными в некоторых контекстах, потому что они не являются частью действительного дерева виджетов. Например, они также часто используются с флажками, группами переключателей и ползунками, обеспечивая доступ к текущим значениям и связывая вместе несколько виджетов. Так уж совпало, что им посвящен следующий раздел.

# 4,

В этом разделе мы использовали два способа компоновки

<* форм: во фреймах по рядам, с метками фиксированной ши-

*’Ч’ <•, рины (entry2), и во фреймах по колонкам (entry3). В главе 9 мы

познакомимся с третьим способом: компоновкой с помощью менеджера grid. Из них наилучший результат на всех платформах обеспечивают компоновка по сетке и по рядам с метками фиксированной ширины, как в сценарии entry2.

Компоновка по колонкам, использованная в сценарии entry3, может использоваться только на платформах, где высота каждой метки в точности соответствует высоте каждого поля ввода. Поскольку эти виджеты напрямую никак не связаны, их вертикальные координаты могут не совпадать на некоторых платформах. Когда я попытался протестировать в системе Linux некоторые формы, замечательно выглядевшие в Windows XP, метки и соответствующие им поля ввода оказались на разной высоте.

Даже такое простое окно, которое воспроизводит сценарий entry3, при ближайшем рассмотрении выглядит несколько кривовато. На некоторых платформах оно только кажется похожим на окно, воспроизводимое сценарием entry2, из-за небольшого количества полей ввода и небольших размеров по умолчанию. В Windows 7 на моем нетбуке несовпадение меток и полей ввода по вертикали становится заметным после добавления 3-4 дополнительных полей ввода в кортеж полей в сценарии entry3.

Если переносимость имеет для вас важное значение, компонуйте свои формы либо с помощью фреймов по рядам и с метками фиксированной/максимальной ширины, как в сценарии entry2, либо с выравниванием виджетов по сетке. Дополнительные примеры таких форм мы увидим в следующей главе. А в главе 12 мы напишем свой инструмент конструирования форм, скрывающий тонкости их компоновки от клиента (включая пример клиента в главе 13).

Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011

Оцените статью
Секреты программирования
Добавить комментарий