18-й час. Графические объекты библиотеки Tk, I

18-й час

Графические объекты библиотеки Tk, I

  В этой главе мы познакомимся с окнами и графическими объектами библиотеки Tkinter. Прочитав главу до конца, Вы сможете отличить окно от графического объекта; различать типы графических объектов; использовать функции обработки событий с объектами Tkinter.

Окна и графические объекты

  Отличить окно от графического объекта очень просто. Окно — это часть экрана, ограниченная каким-либо образом, обычно с помощью видимых границ. За выведение окна на экран отвечает либо диспетчер окон (в X Windows), либо сама операционная система (в Windows). Графический объект — это особый вид окна, снабженного функциональностью. (Не звучит ли это для Вас знакомым?) Обычно графические объекты меньше окон. Примеры окна и графического объекта приведены на рис. 18.1. В действительности различие между окном и графическим объектом условно. Можно сказать, что графический объект — это особый вид окна, снабженного методами.

Рис. 18.1. Окно и графический объект

  Слева на рис. 18.1 показано обычное окно, которое не обладает никакой функциональностью, кроме того, что занимает часть экрана. В этом окне пока что нет ни командных кнопок, ни строки меню. Чтобы отобразить это окно, достаточно ввести и выполнить следующий предельно простой код:

from Tkinter import *

root=Tk()

root.mainloop()

  Единственный способ завершить эту программу — щелкнуть на маленькой кнопке с крестиком в верхнем правом углу окна. Объект справа, это тоже окно, но в него вставлен графический объект — кнопка с надписью "Графический объект". Правда, щелчок на кнопке не приводит ни к каким действиям. (Пример кнопки с назначенной функцией мы рассматривали в предыдущей главе). Код программы отображения данной кнопки показан в листинге 18.1.

Листинг 18.1. Программа tkt3.py

#!C:\PYTHON\PYTHON.EXE

from Tkinter import *

import sys

root=Tk()

button=Button(root)

button["text"]="Графический объект"

button.pack()

root.mainloop()

 

  *Прим. В. Шипкова: позволю себе ещё раз напомнить, что если программист не желает, что бы пользователь увидел абракадабру вместо надписи, то вместо

  button["text"]="Графический объект"

следует написать

  button["text"]=u"Графический объект"

или изначально использовать кодировку utf8

  Как уже говорилось, графические объекты характеризуются состоянием и функциональностью. Они владеют методами, которые можно вызывать, и свойствами, которые можно устанавливать. Если быть точным, то корневое окно, показанное на рис. 18.1, слева, в действительности таковым не является. Это инкапсуляция окна в библиотеке Tkinter, первое производное от корневого окна. Все графические объекты библиотеки Tkinter являются дочерними объектами корневого окна, или, как ещё говорят, — окна верхнего уровня. Это окно обладает базовыми свойствами и функциональностью, которые наследуются дочерним объектам. В деталях наследование объектов в Python мы рассматривали в главах 10 и 11. Все графические объекты библиотеки Tkinter являются обычными программными объектами, характеризующимися состоянием (свойства) и функциональностью (методы). С помощью наследования и изменения функциональности можно создавать такие графические объекты, которые отвечают вашим требованиям.

  Подробную информацию обо всех графических объектах библиотеки Tkinter с указанием всех их свойств и методов можно найти на странице http://www.pythonware.com/library/tkinter/tclass/index.htm.

  В следующих разделах мы подробно рассмотрим все графичеcкие объекты библиотеки Tkinter с примерами простейших программ для их вывода. В главе 19 мы продолжим рассмотрение графических объектов и завершим главу созданием полноценного приложения с интерфейсом GUI. Простейшим из всех графических объектов, пожалуй, является кнопка, показанная на рис. 18.2. Ещё один пример кода вывода кнопки, изображенной на этом рисунке, показан в листинге 18.2.

Объект кнопка

Рис. 18.2. Объект кнопка

from Tkinter import *
import sys

def die(event):
  sys.exit(0)

root = Tk()
button = Button(root)
button["text"] = "Button"
button.bind("<Button>",die)
button.pack()

root.mainloop()

  Код программы tkbutton.py напоминает рассмотренный выше код программы tkt3.py в листинге 18.1, если не считать добавленную функцию завершения программы. Но кнопку можно создать и другим способом. В Tkinter предусмотрена процедура создания графического объекта с синтаксисом вызова функции с параметрами. Вот как можно с помощью одной строки создать кнопку:

button = Button(root, text="Кнопка" ,command=die)

  Этой строкой можно заменить строки 10-12 в листинге 18.2. После создания объекта все его свойства можно устанавливать, используя показанный выше синтаксис словаря: ключ=значение. Единственное, что следует при этом учитывать, так это то, что опция command ожидает имя такой функции обработки события, которая не имеет параметров. Таким образом, если в листинге 18.2 определение объекта кнопки мы заменим на альтернативный однострочный вариант, то также придётся внести изменения в определение функции die(event) и удалить из неё параметр event. В данном случае такие изменения внести не сложно, правда, и сокращение длины кода будет незначительным. Тем не менее альтернативный метод определения графических объектов следует держать на вооружении. Иногда он оказывается весьма эффективным, особенно когда в объекте нужно установить много свойств. С другой стороны, назначение функций обработки событий с помощью метода bind() предпочтительнее. Использование выражения соmаnd=имя_функции ограничивает Ваши возможности назначать только функции без параметров и только единственному событию, тогда как с помощью метода bind() функции обработки можно назначить всем доступным событиям объекта, причём выполнением этих функций можно управлять с помощью параметра.

  Графический объект холст (рис. 18.3) кажется скучным и бесполезным. В действительности это очень интересный объект, позволяющий создавать в нем произвольные рисунки. О том, как это делается, мы узнаем в главах этой части, посвященных графическим функциям библиотеки Tkinter.

Объект холст

Рис. 18.3. Объект холст

  Простейшая программа, с помощью которой в одном окне можно вывести кнопку с холстом, показана в листинге 18.3.

Листинг 18.3. Программа tkcanvas.py

from Tkinter import *

import sys

 

def die(event):

  sys.exit(0)

 

root=Tk()

button=Button(root)

button["text"]="Button"

button.bind("<Button>",die)

button.pack()

canvas=Canvas(root)

canvas["height"]=64

canvas["width"]=64

canvas["borderwidth"]=2

canvas["relief"]=RAISED

canvas.pack()

root.mainloop()

  Свойства height(высота), width(ширина) и другие можно устанавливать в параметрах, как было показано выше на примере объекта кнопки. Впрочем, и в этом случае выигрыш в уменьшении числа строк кода будет незначительным. Установка свойств в параметрах имеет явное преимущество при определении окон сообщений, которые мы рассмотрим в конце этой главы.

Объект флажок

  Флажок, пример которого показан на рис. 18.4, используется в тех случаях, когда от пользователя нужно получить ответ да-нет. Связанные с ними переменные называют переключателями, поскольку для них возможны только два состояния: включена и выключена.

Рис. 18.4. Объект флажок

В листинге 18.4 показано, как можно создать флажок.

Листинг 18.4. Программа tkcheckbutton.py

from Tkinter import *
import sys

def die(event):
  sys.exit(0)

root=Tk()
button=Button(root)
button["text"]="Button"
button.bind("<Button>",die)
button.pack()
checkbutton=Checkbutton(root)
checkbutton["text"]="Checkbutton"
checkbutton.pack()

root.mainloop()

  Следует учесть, что внешний вид большинства графических объектов, если не всех, зависит от операционной системы компьютера. Примеры, представленные в этой книге, были получены на компьютере под управлением Windows. В результате выполнения тех же программ на компьютерах Мас или с системой UNIX будут получены графические объекты, несколько отличающиеся по стилю от приведенных, хотя они вполне узнаваемы. Пример флажка в стиле UNIX показан на рис. 18.5.

Рис. 18.5. Флажок в стиле UNIX

Объект текстовое поле

  Объект текстовое поле (рис. 18.6) принимает текст, введённый пользователем. В поле можно ввести только одну строку, тогда как объект поле редактора, который мы рассмотрим в следующей главе, может принимать несколько строк. В листинге 18.5 показан простейший способ создания текстового поля.

Рис. 18.6. Объект текстовое поле

Листинг 18.5. Программа tkenter.py

#!/usr/local/bin/python

from Tkinter import *
import sys

def die(event):
  print entry.get()
  sys.exit(0)

root = Tk()
button = Button(root)
button["text"] = "Button"
button.bind("<Button>",die)
button.pack()

entry = Entry(root)
entry.insert(0,"Entry")
entry.pack()

root.mainloop()

 

  *Прим. В. Шипкова: обратите внимание на то, как описано положение исполняемого модуля Питона в стиле UNIX. без этой строки, программа, скорей всего, работать не будет. Для пользователей Windows указание местонахождения интерпретатора не актуально.

  После того как щелчком на кнопке "Выход" Вы завершите выполнение программы, она выведет напоследок на печать содержимое текстового поля. Пример того, как получить текущее значение текстового поля и вывести его на печать, показан в строке 7 листинга 18.5. Для считывания значения используется метод get(). Методы get() и set() являются общими для всех графических объектов.

  *Прим. В. Шипкова: здесь имелось в виду "вывод в окно консоли", а не "вывод на принтер".

Объект рамка

  Объект рамка (рис. 18.7) применяется для того, чтобы содержать в себе другие объекты. Его можно использовать также для выделения части экрана. Другими словами, рамки в окнах приложений используются либо как контейнеры, либо как средства оформления.

Рис. 18.7. Объект рамка

  В листинге 18.7 показана простая программа, выводящая рамку. Обратите внимание, что свойства высоты и ширины рамки можно переустановить.

Листинг 18.6. Программа tkframe.py

from Tkinter import *
import sys

def die(event):
  sys.exit(0)

root=Tk()
button=Button(root)
button["text"]="Button"
button.bind("<Button>",die)
button.pack()
frame=Frame(root)
frame["height"]=64
frame["width"]=64
frame["background"]="white"
frame["borderwidth"]=2
frame["relief"]=RAISED
frame.pack()

root.mainloop()

Объект ярлык

  Объект ярлык (рис. 18.8) является, пожалуй, одним из наиболее используемых.

Рис. 18.8. Объект ярлык

  Ярлык содержит неизменяемый текст. Создать его очень просто, как показано в листинге 18.7.

Листинг 18.7. Программа tklabel.py

from Tkinter import *
import sys

def die(event):
  sys.exit(0)

root=Tk()
button=Button(root)
button["text"]="Button"
button.bind("<Button>",die)
button.pack()
labelx=Label(root)
labelx["height"]=1
labelx.pack()
label=Label(root)
label["text"]="Label"
label["borderwidth"]=1
label["relief"]=SOLID

label.pack()

root.mainloop()

  В этой программе для зрительного выделения ярлыка на экране используется дополнительный ярлык без текста labelx. To же самое можно было бы сделать с помощью объекта рамки.

Объект список

  Объект список (рис. 18.9) используется для того, чтобы предоставить пользователю на выбор множество опций. При создании списков всегда проще использовать обычный способ определения, чем установку свойств с помощью параметров.

 

Рис. 18.9. Объект список (рисунок изменён В. Шипковым)

В листинге 18.8 показано, как создать список.

Листинг 18.8. Программа tklistbox.py

from Tkinter import *
import sys

elements=[u"Опция5", u"Опция4", u"Опция3", u"Опция2", u"Опция1"]

def die(event):
  sys.exit(0)

root=Tk()
button=Button(root)
button["text"]=u"Выход"
button.bind("<Button>",die)
button.pack()
labelx=Label(root)
labelx["height"]=1
labelx.pack()

listbox=Listbox(root)
for i in elements :
  listbox.insert(0, i)
  listbox.pack()

root.mainloop()

 

  *Прим. В. Шипкова: хоть названия элементов в списке приведены в обратном порядке, на самом деле Питон их чинтает с конца, поэтому список будет выглядеть к в прямом перечислении, а не наоборот, как этого бы следовало ожидать.

  Цикл for в строке 21 вводит текстовые значения всех опций списка. В действительности существует множество способов введения опций, это только один из них.

Переменные библиотеки Tkinter

  Прежде чем использовать встроенные переменные графических объектов, следует уяснить, что все переменные библиотек Tk/TCL являются строковыми. Они используются во всех тех случаях, когда нужно организовать взаимодействие Python и Tkinter, т.е. в тех случаях, когда графическому объекту необходима переменная, которую он мог бы изменять, используется специальный набор встроенных переменных библиотеки Tkinter. В действительности эти переменные являются не просто строками, а объектами. Все они унаследованы от родительского класса Variable, который содержит ряд базовых методов и атрибутов, свойственных всем другим переменным графических объектов. Каждая такая переменная знает, как устанавливать, обрабатывать и возвращать данные только опредёленного типа. Список переменных библиотеки Tkinter, их описание и примеры создания показаны в табл. 18.1. (Не удивляйтесь, что они выглядят как функции, ведь они все-таки объекты, впрочем, как и все остальные переменные в Python.)

Таблица 18.1. Переменные библиотеки Tkinter

Переменная Описание Пример
StringVar() Сохраняет строки х = StringVar("Текст")
IntVar() Сохраняет целые значения х = IntVar(42)
DoubleVar() Сохраняет значения с плавающей запятой х = DoubleVar(3.14159)
BooleanVar() Сохраняет значения true и false (истинно и ложно) х = BooleanVar("true")

  Чтобы возвратить значение любой из этих переменных, используется метод get(), например print x.get(). Для изменения значения используется метод set(), например x.set(2*pi). Как Вы увидите ниже, обмен данными со всеми графическими объектами (как передача, так и возвращение) осуществляется только с помощью переменных библиотеки Tk.

Объекты меню и кнопка меню

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

Рис. 18.10. Строка меню

  Вы видели подобную строку меню во всех приложениях для Windows. В лситинге 18.9 показано, как её можно создать.

Листинг 18.9. Программа tkmenu.py

from Tkinter import *
import tkMessageBox
import sys

def die():
  sys.exit(0)

def callee():
  print u"Я был вызван!"

def about():
  tkMessageBox.showinfo("tkmenu",u"Это tkmenu.py \

    Версия 0")

root=Tk()
bar=Menu(root)

filem = Menu(bar)
filem.add_command(label=u"Открыть...", command=callee)
filem.add_command(label=u"Новый...", command=callee)
filem.add_command(label=u"Сохранить", command=callee)
filem.add_command(label=u"Сохранить как...",\

 command=callee)
filem.add_separator()
filem.add_command(label=u"Выход", command=die)

helpm = Menu(bar)
helpm.add_command(label=u"Индекс...", command=callee)
helpm.add_separator()
helpm.add_command(label=u"О программе", command=about)

bar.add_cascade(label=u"Файл", menu=filem)
bar.add_cascade(label=u"Помощь", menu=helpm)

root.config(menu=bar)
root.mainloop()

 

  *Прим. В. Шипкова: прошу обратить внимание на строку:

  print u"Я был вызван!"

Я указал Python, что строка является юникодом, хотя на самом деле эта строка может быть В ЛЮБОЙ КОДИРОВКЕ. Питон старательно переведёт её в юникод, а затем в классический ASCII (т. е. кодировку пригодную для консоли). Поэтому при выводе строки на консоль будет отображаться ПРАВИЛЬНЫЙ текст. Говоря проще, Питон - это сила! :)

  В строках 13, 14 показан особый вид функции обработки события, которая возвращает сообщение после выбора команды "0 программе". В этом случае вызывается графический объект окна сообщения, о котором мы поговорим далее в этой главе. В строке 19 создаётся объект меню filem, который является контейнером для ряда объектов кнопок меню, добавляемых в объект меню в строках 20-25. В строке 24 добавляется разделитель, который на экране выглядит как простая линия, отделяющая последнюю опцию "Выход" ото всех остальных опций меню "Файл". Как видите, нам не пришлось даже напрямую вызывать Menubutton(). Вместо этого вызова используется встроенный метод объекта меню add_command(). Вызов функции Menubutton() также возможен, но наш подход проще.

  В строках 27-30 создаётся второй объект меню helpm, а в строках 32, 33 два объекта меню добавляются в объект строки меню bar, который был произведён от корневого окна в строке 17. Для добавления объектов меню в строку меню используется метод add_cascade(), который в действительности добавляет не сами объекты меню, а ярлыки, связанные с соответствующими объектами. Щелчок на ярлыке раскрывает связанное с ним меню, пример которого показан на рис. 18.11.

Рис. 18. 11. Раскрывающееся меню

  Можно назначить опциям раскрывающегося меню другое вложенное раскрывающееся меню, которое будет содержать свои объекты Menubutton (кнопки меню). Но я лично не сторонник такого стиля. Меню чувствительно к перемещению мыши, а создание сложной системы вложенных меню не лучшим образом реализует эту зависимость. Не знаю, как Вас, а меня всегда раздражают ненужные мне подменю, всплывающие на экране, когда я провожу указателем по опциям главного меню. Зато когда мне нужно что-то выбрать в подменю, оно предательски исчезает, из-за того что указатель соскользнул на главное меню. Мне гораздо больше по душе стиль, когда команды меню открывают диалоговые окна с наборами дополнительных опций. Кстати, по общепринятому соглашению за такими командами меню ставится многоточие, как показано на рис. 18.11 на примере опции Создать... . Те опции, которые открывают вложенные подменю, принято выделять стрелками. Таким образом, объекты меню помимо кнопок могут содержать объекты вложенных меню, флажки, переключатели и разделители.

  Меню опций (рис. 18.12) создаётся несколько сложнее. Хотя это и не обязательно, но обычно для установки ярлыка меню опций используется переменная графических объектов Tkinter. Если строка меню, как правило, располагается в верхней части окна программы или в виде плавающего диалогового окна, то меню опций может располагаться где угодно. В листинге 18.10 представлен код программы, создающей меню опций, показанное на рис. 18.12.

Рис. 18.12. Меню опций

Листинг 18.10. Программа tkoptionmenu.py

from Tkinter import *
import tkMessageBox
import sys

def die():
  global xx
  print xx.get()
  sys.exit(0)

def callee():
  print "I was called; few are chosen"

def about():
  tkMessageBox.showinfo("tkmenu","This is tkmenu.py\

   Version 0")

root=Tk()
bar=Menu(root)

filem=Menu(bar)
filem.add_command(label="Open...", command=callee)
filem.add_command(label="New...", command=callee)
filem.add_command(label="Save", command=callee)
filem.add_command(label="Save as...", command=callee)
filem.add_separator()
filem.add_command(label="Exit", command=die)

helpm=Menu(bar)
helpm.add_command(label="Index...", command=callee)
helpm.add_separator()
helpm.add_command(label="About", command=about)

bar.add_cascade(label="File", menu=filem)
bar.add_cascade(label="Help", menu=helpm)

root.config(menu=bar)
frame = Frame(root)
frame.pack()
xx = StringVar(frame)
xx.set("slow")

fm=OptionMenu(frame, xx, "slow", "slower", "slowest", \

  "even  slower")
fm.pack()
root.mainloop()

  Как видите, данная программа выводит ту же строку меню, что и программа tkmenu.py из листинга 18.9. Но в программу tkoptionmenu.py добавлены дополнительные строки кода, создающие меню опций. В строке 40 создаётся строковая переменная графического объекта Tkinter, которая затем используется в строке 43. Вторым аргументом в вызове OptionMenu() должна быть переменная Tkinter, которой в строке 41 присваивается значение "нормально". Таким образом, устанавливается значение по умолчанию для меню опций. При выборе другой опции меню автоматически изменяется значение переменной хх. В строках 8, 9 показано, как возвратить это значение и вывести на печать.

Объекты окон сообщений

  Окна сообщений являются монопольными диалоговыми окнами, которые всплывают поверх основного окна приложения и прерывают выполнение программы до тех пор, пока пользователь не щелкнет на одной из кнопок, представленных в окне. Кнопкой, выбираемой по умолчанию, для большинства окон сообщений является ОК. Но это не обязательно. Кроме того, есть окна сообщений, где эта кнопка вообще отсутствует, как, например, в окнах типа "Да-Нет", в которых представлены только две кнопки: Да и Нет. Свойства окон сообщений проще всего устанавливать как параметры функции tkMessageBox.showinfo(). Пример такого подхода Вы уже видели в строке 16 листинга 18.10. Иногда полезно использовать непосредственно функцию Messagebox(), например при создании окна вопроса, которое мы рассмотрим далее в этой главе. Обратите внимание, что все окна сообщений, показанные на рисунках ниже, были получены в системе Windows. Те же окна в UNIX будут выглядеть немного иначе. Они будут отличаться хотя бы тем, что в UNIX используются черно-белые пиктограммы, а не цветные, как в Windows. Но приведенные ниже функции подходят для любой операционной системы и платформы.

Информационное окно сообщения

  Код создания информационного окна сообщения показан в листинге 18.11.

Листинг 18.11. Программа tkmessage.info.py

from Tkinter import *
import tkMessageBox
import sys

def die(event):
  tkMessageBox.showinfo("tkMessageBox", "tkMessageBox.showinfo")
  sys.exit(0)

root = Tk()
button = Button(root)
button["text"] = "Button"
button.bind("<Button>",die)
button.pack()

root.mainloop()

  Первый параметр функции showinfo() (см. строку 8) устанавливает заголовок окна, а со вторым параметром передаётся текст сообщения, которое будет выведено в окне. На рис. 18.13 показан результат выполнения программы tkmessage.info.py.

Рис. 18.13. Информационное окно сообщения

Большинство других окон сообщений такие же простые.

Предупреждающее окно сообщения

Предупреждающее окно сообщения показано на рис. 18.14.

Рис. 18.14. Предупреждающее окно сообщения

В листинге 18.12 показан код программы предупреждающего окна сообщения.

from Tkinter import *
import tkMessageBox
import sys

def die(event):
  tkMessageBox.showwarning("tkMessageBox","tkMessageBox.showwarning")
  sys.exit(0)

root = Tk()
button = Button(root)
button["text"] = "Button"
button.bind("<Button>",die)
button.pack()

root.mainloop()

  Как видите, от предыдущего листинга эта программа отличается только строкой 8.

Окно сообщения об ошибке

Пример окна сообщения об ошибке показан на рис. 18.15.

Рис. 18.15. Окно сообщения об ошибке

  Окно сообщения об ошибке также содержит лишь одну кнопку ОК. Вы можете только прочитать сообщение и убрать его с экрана, иногда вместе с программой. Код вывода этого окна показан в листинге 18.13.

Листинг 18.13. Программа tkmessage.error.py

from Tkinter import *
import tkMessageBox
import sys

def die(event):
  tkMessageBox.showerror("tkMessageBox","tkMessageBox.showerror")
  sys.exit(0)

root = Tk()
button = Button(root)
button["text"] = "Button"
button.bind("<Button>",die)
button.pack()

root.mainloop()

  И вновь,отличие коснулось только строки 8. Все три окна сообщений, рассмотренные выше, имели много общего. Все они содержали единственную кнопку ОК. От пользователя не ожидалось никаких действий, кроме того, что он должен прочесть сообщение и закрыть окно. В случае с сообщением об ошибке, вероятно, Вам следует установить автоматическое закрытие и само приложение, в котором произошла ошибка, если только Вы не уверены, что ничего страшного не произойдет и пользователь не потеряет свои данные. Окна сообщений следующей группы содержат больше одной кнопки, что позволяет пользователю сделать свой выбор.

Окно сообщения типа "Да-Нет"

  Окно сообщения, показанное на рис. 18.16, предлагает пользователю прямо ответить на вопрос: да или нет.

Рис. 18.16. Окно сообщения типа "Да-Нет"

Код программы показан в листинге 18.14.

Листинг 18.14. Программа tkmessage.askyesno.py

from Tkinter import *
import tkMessageBox
import sys

def die(event):
  response = tkMessageBox.askyesno("tkMessageBox",
"tkMessageBox.askyesno")
 
print response
  sys.exit(0)

root=Tk()
button=Button(root)
button["text"]="Button"
button.bind("<Button>",die)
button.pack()

root.mainloop()

  После выполнения программы Вы увидите, что выбор кнопки "Да" возвратит значение 1, а выбор кнопки "Нет" — значение 0. Эти значения, соответствующие выбранной пользователем кнопке, возвращаются функцией askyesno() в строке 8. Далее Вы сможете установить путь выполнения программы в зависимости от выбора пользователя, воспользовавшись инструкцией if.

Окно сообщения типа "Ок-Отмена"

  Следующее окно сообщения, показанное на рис. 18.17, также содержит только две кнопки, но называются они иначе.

Рис. 18.17. Окно сообщения типа "Ок-Отмена"

  В листинге 18.15 показан код программы вывода этого окна (как видите, данный код аналогичен для всех двухкнопочных окон сообщений).

Листинг 18.15. Программа tkmessage.askokcancel.py

from Tkinter import *
import tkMessageBox
import sys

def die(event):
  r = tkMessageBox.askokcancel("tkMessageBox", "tkMessageBox.askokcancel")
 
print r
  sys.exit(0)

root = Tk()
button = Button(root)
button["text"] = "Button"
button.bind("<Button>",die)
button.pack()

root.mainloop()

 

Окно сообщения типа "Повтор-Отмена"

  Ещё одно двухкнопочное окно сообщения показано на рис. 18.18. Принцип его работы аналогичен предыдущему.

Рис. 18.18. Окно сообщения типа Повтор-Отмена

Код программы показан в листинге 18.16.

from Tkinter import *
import tkMessageBox
import sys

def die(event):
  r = tkMessageBox.askretrycancel("tkMessageBox", \
  "tkMessageBox.askretrycancel")
 
print r
  sys.exit(0)

root = Tk()
button = Button(root)
button["text"] = "Button"
button.bind("<Button>",die)
button.pack()

root.mainloop()

  Все три двухкнопочных окна сообщения используются совершенно одинаково. На вопрос, поставленный в сообщении, пользователь может ответить щелчком на одной из двух кнопок. Других возможностей закрыть окно у него просто нет, разве что выключить компьютер. В результате объект окна возвращает одно из двух значений: 0 или 1. Вам осталось только запомнить, что значение 0 соответствует выбору кнопок "Нет", "Отмена", "Пропустить", а значение 1 — кнопкам "ОК", "Да", "Повтор".

Окно вопроса

  Чтобы отобразить трёхнопочное окно, показанное на рис. 18.19, необходимо напрямую обратиться к методу Messaged, поскольку не существует специальных функций вывода окон, содержащих больше двух кнопок. Обратите внимание, что в этом случае весьма удобно использовать стиль назначения свойств в параметрах вызова функции.

Рис. 18. 19. Окно вопроса Код программы показан в листинге 18.17.

Листинг 18.17. Программа tkmessage.askquestion.py

from Tkinter import *
import tkMessageBox
import sys

def die(event):
  x = tkMessageBox.Message(root,\

    type=tkMessageBox.ABORTRETRYIGNORE, \

    icon=tkMessageBox.QUESTION,\

    title="tkMessageBox",\

    message="tkMessageBox.askquestion")
    r = x.show()
    tkMessageBox.showinfo("Reply", r )
    sys.exit(0)

root = Tk()
button = Button(root)
button["text"] = "Button"
button.bind("<Button>",die)
button.pack()

root.mainloop()

  Свойства окна сообщения устанавливаются в строках 8-11. Свойству type присвоено значение константы ABORTRETRYIGNORE, что означает трехкнопочное окно с кнопками "Стоп", "Повтор", "Пропустить". Ещё одна константа QUESTION устанавливает для свойства icon вид отображаемой пиктограммы — знак вопроса. Эти две константы определены в модуле tkMessageBox. Далее устанавливаются заголовок окна и текст сообщения соответственно для свойств "title" и "message". Эти свойства ожидают получить строковые значения. В данном случае нам ещё необходимо выполнить две операции, которые раньше выполнялись автоматически функциями показа окон. Во-первых, нужно самостоятельно создать объект окна сообщения х (х = tkMessageBox.Message()), а во-вторых, вызвать метод x.show(). В строке 12 мы не только вызываем метод show(), но и присваиваем возвращенное им значение переменной r. Затем мы используем специальную функцию показа окна сообщений showinfo(), чтобы отобразить значение выбранной кнопки на экране. Выполните программу и обратите внимание на то, что r является строкой, а не числом. Это ещё одно отличие между использованием метода Message и специальной функции показа окна сообщения.

  В действительности такой подход можно использовать для показа всех окон сообщения. Специальные функции выполняют лишь роль удобного интерфейса между пользователем и методом Message().

Резюме

  Мы рассмотрели различные типы базовых графических объектов библиотеки Tkinter — от кнопки до различных видов окон сообщений. В следующей главе мы завершим эту тему, рассмотрев такие графические объекты, как переключатель и поле редактора, после чего попытаемся создать полнофункциональное приложение, демонстрирующее использование всех рассмотренных объектов в графическом пользовательском интерфейсе.

Практикум

Вопросы и ответы

  Почему одни и те же графические объекты по-разному1 выглядят в Windows, X Windows и Mac?

  Первоначально графические объекты в системах Windows и X Windows выглядели почти одинаково, поскольку корнями уходили к общему предку — объектам, разработанным в компании HP. Но в дальнейшем они развивались разными путями. В X Windows они выглядят более упрощенно в так называемом стиле Motif. На графические объекты Windows сильное влияние оказали разработки компании Macintosh, где использовались графические объекты, разработанные в исследовательской лаборатории Palo Alto компании Xerox (Xerox's Palo Alto Research lab). В сочетании с классами Windows эти объекты видоизменялись от версии Windows 3.1 до Windows 95. Изначально в библиотеке Tk/TCL использовались графические объекты, которые выглядели совершенно одинаково во всех системах и на всех платформах. Но затем были разработаны объекты, отвечающие стилю текущей системы. Благодаря этому поддерживается эмоциональная сторона свойства переносимости программных продуктов на языке Python, т.е. программы не только успешно выполняются независимо от операционной системы, но и пользовательский интерфейс выглядит как родной.

  В приложениях для Windows часто применяются списки, снабжённые полосой прокрутки. Что это такое — графический объект или их комбинация, и можно ли нечто подобное сделать в Python?

  Такой объект называется комбинированным списком. В Tkinter нет аналогичного графического объекта, который можно было бы непосредственно использовать, но в принципе его можно разработать самостоятельно. Наиболее удачной в этом плане мне кажется разработка Грега Мак-Фарлана (Greg McFarlane) из Австралии, который собрал целую коллекцию комбинированных графических объектов и назвал её Python Megawidgets. В этой коллекции можно найти и комбинированный список. Посетите домашнюю страницу Python Megawidgets по адресу http://www.dscpl.com.au/pmw/. Сам Грег так охарактеризовал свою коллекцию: "Она построена на базовых графических объектах Tkinter и содержит классы и библиотеки легко настраиваемых и расширяемых графических объектов. В коллекции Вы можете найти различные варианты записных книжек, раскрывающихся и комбинированных списков, полос прокрутки, диалоговых окон и многое другое". Следует добавить, что классы всех этих объектов написаны исключительно на Python без блоков на языке С, что чрезвычайно важно для тех пользователей, у которых нет компилятора С или C++.

Контрольные вопросы

  1. Какие графические объекты работают по принципу переключателя?

    а) Кнопка.

    б) Список.

    в) Флажок.

    г) Текстовое поле.

  2. Какая разница между строкой меню и меню опций?

    а) Строка меню расположе-на в верхней части главного окна приложения, тогда как меню опций находится внизу.

    б) Строка меню раскрывается вниз, а меню опций — в сторону.

    в) Меню опций может быть расположено в любой части окна приложения, тогда как строка меню всегда находится вверху окна под строкой заголовка.

    г) Это разные названия одного и того же объекта.

Ответы

  1. в. Флажок работает как переключатель, так как имеет только два состояния — выбран и не выбран.

  2. в. Меню опций может быть расположено в любой части окна приложения, тогда как строка меню всегда находится вверху окна под строкой заголовка.

Примеры и задания

  Разыщите информацию об истории развития графического пользовательского интерфейса. Начните с Web-страницы Майкла Хофмана (Michael S. Hoffman) The UNIX GUI Manifesto (Манифест UNIX GUI), расположенной по адресу http://vww.cybtrans.com/infostrc/unixgui.htm.