Курс по библиотеке Tkinter языка Python

## Введение

Этой библиотеке посвящено мало внимания, и найти в рунете курс, книгу или FAQ по ней довольно-таки сложно. Стоит отметить, что здесь отражены только основы этой библиотеки, и надеюсь, что более опытные люди дополнят эту статью.

## Что такое tkinter?

Tkinter - это графическая библиотека, позволяющая создавать программы с оконным интерфейсом. Эта библиотека только перенесена на Python, она широко известна в мире UNIX-систем, и для её изучения можно использовать туториалы для этих систем. Импортируется она как и любая другая библиотека:

```
import Tkinter
```

или

```
from Tkinter import *
```

В Tkinter визуальные контроллы называются виджетами - стандартизированный компонент графического пользовательского интерфейса, с которым взаимодействует пользователь.

## Основные виджеты

### Button

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

```
from Tkinter import *
root=Tk()
button1=Button(root,text='ok',width=25,height=5,bg='black',fg='red',font='arial 14')
button1.pack()
root.mainloop()
```

Разберем этот небольшой код. За создание, собственно, окна, отвечает класс Tk(), и первым делом нужно создать экземпляр этого класса. Этот экземпляр принято называть root, хотя вы можете назвать его как угодно. Далее создаётся кнопка, при этом мы указываем её свойства(начинать нужно с указания окна, в примере - root). Здесь перечислены некоторые из них:

- text - какой текст будет отображён на кнопке (в примере - ок)
- width,height - соответственно, ширина и длина кнопки.
- bg - цвет кнопки (сокращенно от background, в примере цвет - чёрный)
- fg - цвет текста на кнопке (сокращённо от foreground, в примере цвет - красный)
- font - шрифт и его размер (в примере - arial, размер - 14)

Далее, нашу кнопку необходимо разместить на окне. Для этого, в Tkinter используются специальные *упаковщики*( pack(),place(), grid() ). Поподробнее об упаковщиках узнаем позже. Пока, чтобы разместить несколько виджетов на окне, будем применять самый простой упаковщик pack(). В конце программы, нужно использовать функцию mainloop(см. пример), иначе окно не будет создано.

### Label

Label - это виджет, предназначенный для отображения какой-либо надписи без возможности редактирования пользователем. Имеет те же свойства, что и перечисленные свойства кнопки.

### Entry

Entry - это виджет, позволяющий пользователю ввести одну строку текста. Имеет дополнительное свойство bd (сокращённо от borderwidth), позволяющее регулировать ширину границы.

### Text

Text - это виджет, который позволяет пользователю ввести любое количество текста. Имеет дополнительное свойство wrap, отвечающее за перенос (чтобы, например, переносить по словам, нужно использовать значение WORD).Например:

```
from Tkinter import *
root=Tk()
text1=Text(root,height=7,width=7,font='Arial 14',wrap=WORD)
text1.pack()
root.mainloop()
```

### Listbox

Listbox - это виджет, который представляет из себя список, из элементов которого пользователь может выбирать один или несколько пунктов. Имеет дополнительное свойство selectmode, которое, при значении SINGLE, позволяет пользователю выбрать только один элемент списка, а при значении EXTENDED - любое количество. Пример:

```
from Tkinter import *
root=Tk()
listbox1=Listbox(root,height=5,width=15,selectmode=EXTENDED)
listbox2=Listbox(root,height=5,width=15,selectmode=SINGLE)
list1=[u"Москва",u"Санкт-Петербург",u"Саратов",u"Омск"]
list2=[u"Канберра",u"Сидней",u"Мельбурн",u"Аделаида"]
for i in list1:
listbox1.insert(END,i)
for i in list2:
listbox2.insert(END,i)
listbox1.pack()
listbox2.pack()
root.mainloop()
```

Стоит заметить, что в этой библиотеке для того, чтобы использовать русские буквы в строках, нужно использовать Unicode-строки. В Python 2.x для этого нужно перед строкой поставить букву u, в Python 3.x этого делать вообще не требуется, т.к. все строки в нем изначально Unicode.

### Frame

Виджет Frame (рамка) предназначен для организации виджетов внутри окна. Рассмотрим пример:

```
from Tkinter import *
root=Tk()
frame1=Frame(root,width=100,height=100,bg='green',bd=5)
frame2=Frame(root,width=150,height=75,bg='red',bd=5)
button1=Button(frame1,text=u'Первая кнопка')
button2=Button(frame2,text=u'Вторая кнопка')
frame1.pack()
frame2.pack()
button1.pack()
button2.pack()
root.mainloop()
```

Свойство bd отвечает за расстояние от края рамки до виджетов.

### Checkbutton

Checkbutton - это виджет, который позволяет отметить „галочкой“ определенный пункт в окне. При использовании нескольких пунктов нужно каждому присвоить свою переменную. Разберем пример:

```
from Tkinter import *
root=Tk()
var1=IntVar()
var2=IntVar()
check1=Checkbutton(root,text=u'1 пункт',variable=var1,onvalue=1,offvalue=0)
check2=Checkbutton(root,text=u'2 пункт',variable=var2,onvalue=1,offvalue=0)
check1.pack()
check2.pack()
root.mainloop()
```

IntVar() - специальный класс библиотеки для работы с целыми числами. variable - свойство, отвечающее за прикрепление к виджету переменной. onvalue, offvalue - свойства, которые присваивают прикреплённой к виджету переменной значение, которое зависит от состояния(onvalue - при выбранном пункте, offvalue - при невыбранном пункте).

### Radiobutton

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

```
from Tkinter import *
root=Tk()
var=IntVar()
rbutton1=Radiobutton(root,text='1',variable=var,value=1)
rbutton2=Radiobutton(root,text='2',variable=var,value=2)
rbutton3=Radiobutton(root,text='3',variable=var,value=3)
rbutton1.pack()
rbutton2.pack()
rbutton3.pack()
root.mainloop()
```

В этом виджете используется уже одна переменная. В зависимости от того, какой пункт выбран, она меняет своё значение. Самое интересное, что если присвоить этой переменной какое-либо значение, поменяется и выбранный виджет. На этом мы прервём изучение типов виджетов (потом мы к ним обязательно вернёмся).

## Упаковщики

Упаковщик - это специальная подпрограмма, которая размещает (упаковывает) виджеты на окне. Как и говорилось ранее, в Tkinter есть три упаковщика: pack(), place(), grid(). Разберем каждый из них по порядку:

### pack()

Упаковщик pack() является самым простым в основном потому, что его можно вызвать без указания свойств(что мы и делали ранее). Основная задача этого упаковщика - указать, с какой стороны находится виджет, относительно виджетов, находящихся после него, с помощью свойства side. Например:

```
button1.pack(side='left')
button2.pack()
```

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

### place()

При использовании этого упаковщика, нам необходимо указывать координаты каждого виджета. Например:

```
button1.place(x='0',y='0')
```

Этот упаковщик, хоть и кажется неудобным, предоставляет полную свободу в размещении виджетов на окне. Перейдем к самому (на мой взгляд) эффективному упаковщику - grid()

### grid()

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

- row - строка
- column - столбец
- columnspan - сколько ячеек занимает виджет. (необязательный аргумент)

Для каждого виджета указываем, в какой он находится строке, и в каком столбце. Если нужно, указываем, сколько ячеек он занимает (если, например, нам нужно разместить три виджета под одним, необходимо "растянуть" верхний на три ячейки). Например:

```
entry1.grid(row=0,column=0,columnspan=3)
button1.grid(row=1,column=0)
button2.grid(row=1,column=1)
button3.grid(row=1,column=2)
```

## Привязка событий

"Всё это хорошо" - наверное, подумали вы -"Но как сделать так, чтобы мои виджеты что-то делали, а не просто красовались на окне?". В Tkinter есть специальный метод, привязывающий событие к какому-либо действию. Этот метод - bind()

### bind()

Метод bind привязывает событие к какому-либо действию (будь то нажатие кнопки мыши, клавиши и т.д.). Вот основные действия:

- <Button-1> - нажатие левой кнопки мыши
- <Button-3> - нажатие правой кнопки мыши
- <Button-2> - нажатие на колесико мыши
- <Return> - нажатие клавиши Enter
- <Motion> - движение мышкой
- <Control> - нажатие клавиши Ctrl
- <Shift> - нажатие клавиши Shift
- <z> - нажатие клавиши z (вместо z можно использовать любой символ)

Если вы хотите, чтобы событие возникало при нажатии комбинации клавиш, нужно указать их через тире, например:

- <Control-a>

Событие описывается обычной функцией. Например:

```
from Tkinter import *
root=Tk()
def leftclick(root):
print 'Вы нажали левую кнопку мыши'
def rightclick(root):
print 'Вы нажали правую кнопку мыши'
button1=Button(root, text=u'Нажми')
button1.pack()
button1.bind('<Button-1>',leftclick)
button1.bind('<Button-3>',rightclick)
root.mainloop()
```

## Продвинутые виджеты

Эти виджеты можно увидеть в меньшем количестве программ, однако они иногда здорово облегчают жизнь.

### Scale

Scale (шкала) - это виджет, позволяющий выбрать какое-либо значение из заданного диапазона. Свойства:

- orient - как расположена шкала на окне. Возможные значения: HORIZONTAL, VERTICAL (горизонтально, вертикально).
- length - длина шкалы.
- from_ - с какого значения начинается шкала.
- to - каким значением заканчивается шкала.
- tickinterval - интервал, через который отображаются метки шкалы.
- resolution - шаг передвижения (минимальная длина, на которую можно передвинуть движок)

Пример кода:

```
from Tkinter import *
root = Tk()
def getV(root):
a = scale1.get()
print "Значение", a
scale1 = Scale(root,orient=HORIZONTAL,length=300,from_=50,to=80,tickinterval=5,
resolution=5)
button1 = Button(root,text=u"Получить значение")
scale1.pack()
button1.pack()
button1.bind("<Button-1>",getV)
root.mainloop()
```

Здесь используется специальный метод get(), который позволяет снять с виджета определенное значение, и используется не только в Scale.

### Scrollbar

Этот виджет даёт возможность пользователю "прокрутить" другой виджет (например текстовое поле) и часто бывает полезен. Реализация этого виджета достаточно оригинальна (рассмотрим её на примере):

```
from Tkinter import *
root = Tk()
text1 = Text(root,height=3,width=60)
scr1 = Scrollbar(root,command=text1.yview)
text1.configure(yscrollcommand=scr1.set)
text1.pack(side='left')
scr1.pack()
root.mainloop()
```

Мы указываем свойством command, какой виджет будет прокручиваться и привязываем Scrollbar к текстовому полю при помощи команды set().

## Ссылки

An Introduction to Tkinter (англ.) — хорошее дополнение к документации