В Python есть довольно много GUI фреймворков (graphical user interface), однако только Tkinter встроен в стандартную библиотеку языка. У Tkinter есть несколько преимуществ. Он кроссплатформенный, поэтому один и тот же код можно использовать на Windows, macOS и Linux.
Визуальные элементы отображаются через собственные элементы текущей операционной системы, поэтому приложения, созданные с помощью Tkinter, выглядят так, как будто они принадлежат той платформе, на которой они работают.
Хотя Tkinter является популярным GUI фреймворком на Python, у него есть свои недостатки. Один из них заключается в том, что графические интерфейсы, созданные с использованием Tkinter, выглядят устаревшими. Если вам нужен современный, броский интерфейс, то Tkinter может оказаться не совсем тем, для этого есть PyQt5 который развивается сильнее в данном плане.
Есть вопросы по Python?
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Telegram Чат & Канал
Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!
Паблик VK
Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!
Тем не менее, в плане использования, Tkinter является относительно легким по сравнению с другими библиотеками. Это отличный выбор для создания GUI приложений в Python, особенно если современный облик не в приоритете для программы, а большую роль играет функциональность и кроссплатформенная скорость.
Другие статьи по Tkinter на сайте
- Создание окна по центру и кнопка выхода в Tkinter
- Разметка виджетов в Tkinter — pack, grid и place
- Виджеты Checkbutton, Label, Scale и Listbox в Tkinter
- Меню, подменю и панель инструментов в Tkinter
- Диалоговые окна в Tkinter
- Рисуем линии, прямоугольники, круг и текст в Tkinter
- Пишем игру змейка на Tkinter
Основные аспекты руководства
- Введение и создание простого приложения «Hello, World!» в Tkinter;
- Работа с виджетами вроде кнопок или текстовых боксов;
- Управление макетом приложений через геометрические менеджеры;
- Создание интерактивного приложения через связывание кнопок с функциями Python.
После освоения основных навыков в процессе изучения примеров, данных в руководстве, вы сможете создать два рабочих приложения. Одно будет конвертером температуры, а второе редактором текста. Что ж, приступим!
Создание простого GUI приложения на Tkinter
Главным элементом GUI Tkinter является окно. Окнами называют контейнеры, в которых находятся все GUI элементы. Данные GUI элементы, к числу которых относятся текстовые боксы, ярлыки и кнопки, называются виджетами. Виджеты помещаются внутри окон.
Сперва создадим окно с одним виджетом. Запустим новую сессию оболочки Python, следуя инструкции.
На заметку: Примеры кода, используемые в руководстве, были протестированы на Windows, macOS и Ubuntu Linux 18.04 через версии Python 3.6, 3.7 и 3.8.
В случае, если вы установили Python на Windows или macOS, скачав установщик c официального сайта python.org, проблем с запуском кода из примеров возникнуть не должно. Можете пропустить оставшуюся часть заметки и перейти к самому руководству.
В случае, если ввиду отсутствия официальных дистрибутивов Python для вашей системы, вы установили Python иным образом, тогда обратите внимание на следующие моменты.
Установка Python на macOS используя Homebrew:
Дистрибутив Python для macOS, доступный на Homebrew, поставляется без библиотеки Tcl/Tk с Tkinter. Вместо этого используется версия системы по умолчанию. Версия может быть устаревшей и не позволяющей импортировать модуль Tkinter в Python. Во избежание такой проблемы, используйте официальный установщик macOS.
Ubuntu Linux 16.04:
Последняя версия Python доступна на Ubuntu Linux 16.04, это 3.5. Вы можете установить последнюю версию через deadsnakes PPA. Далее даны команды для установки PPA и загрузки последней версии Python с правильной версией Tcl/Tk:
$ sudo add—apt—repository ppa:deadsnakes/ppa
$ sudo apt—get update
$ sudo apt—get install python3.8 python3—tk
Первые две команды добавляют deadsnakes PPA в ваш системный список репозитория, а последняя команда устанавливает Python 3.8 и модуль GUI Tkinter.
Ubuntu Linux 18.04:
Вы можете установить последнюю версию Python с соответствующей версией Tcl/Tk из универсального репозитория через следующую команду:
$ sudo apt—get install python3.8 python3—tk
Таким образом устанавливается Python 3.8, а также модуль Tkinter.
Прочие версии Linux:
Если на данный момент нет официального рабочего установщика Python для Linux дистрибутива, то можете поставить Python вместе с соответствующей версией Tcl/Tk через исходный код. С пошаговой инструкцией процесса можете ознакомиться на странице: Установка Python 3.8 из исходного кода на Linux
В открытой оболочке IDLE Python первым делом необходимо импортировать модуль Tkinter:
Окно, или window является экземпляром класса Tkinter. Попробуйте создать новое окно, присвоив его переменной окна window
:
При выполнении вышеуказанного кода на экране появится новое окно. То, как оно будет выглядеть, зависит от вашей операционной системы:
Далее в руководстве будут представлены примеры из операционной системы Ubuntu и Windows.
Добавление нового виджета в приложении
Теперь, когда у вас есть окно, можно добавить на него виджет. Используем класс tk.Label
и добавим какой либо текст на окно.
Создадим виджет ярлыка (label) с текстом "Привет, Tkinter!"
и присвоим его переменной под названием greeting
:
>>> greeting = tk.Label(text=«Привет, Tkinter!») |
Созданное ранее окно не меняется. Создается виджет ярлыка, однако пока не добавляется на окно. Есть несколько способов добавления виджетов на окно. Сейчас можно использовать метод .pack()
от виджета ярлыка:
Теперь окно выглядит следующим образом:
При использовании метода .pack()
для размещения виджета в окне, Tkinter устанавливает размер окна настолько маленьким, насколько возможно, пока в него не влезает виджет. Теперь выполним следующее:
Кажется, будто ничего не случилось, но это не совсем так. window.mainloop()
указывает Python, что нужно запустить цикл событий Tkinter. Данный метод требуется для событий вроде нажатий на клавиши или кнопки, он также блокирует запуск любого кода, что следует после, пока окно, на котором оно было вызвано, не будет закрыто. Попробуйте закрыть созданное окно, и вы увидите появившуюся в оболочке подсказку.
Внимание: При работе с Tkinter из Python REPL окна обновляются при выполнении каждой строки. Однако, если программа Tkinter выполняется из запущенного файла, такого не происходит.
Если не добавлять
window.mainloop()
в конец программы в Python файле, тогда приложение Tkinter не запустится вообще, и ничего не будет отображаться.
Для создания окна в Tkinter, нужно всего несколько строк кода. Тем не менее, в пустое окно нам ничем не поможет! В следующем разделе будут рассмотрены некоторые виджеты, доступные в Tkinter, а также способы их настройки при добавлении в приложение.
Выполните небольшое задание, чтобы проверить свои знания.
Напишите полный скрипт для создания окна в Tkinter с текстом «Python рулит!». Окно должно выглядеть следующим образом:
Попробуйте выполнить задание самостоятельно. Затем можете сравнить свой код с решением, представленным ниже. Помните, что у каждого программиста есть свой стиль, и ваша программа вовсе не обязана выглядеть точно так же, как код из следующего примера.
Код с решением
import tkinter as tk window = tk.Tk() label = tk.Label(text=«Python рулит!») label.pack() window.mainloop() |
Работа с виджетами в Tkinter
Виджеты являются основой GUI фреймворка Tkinter в Python. Это элементы, через которые пользователи взаимодействуют с программой. В Tkinter каждый виджет определен классом. Далее представлен список популярных виджетов из Tkinter:
Класс виджета | Описание |
---|---|
Label | Используется для отображения текста или вставки изображения на окне приложения. |
Button | Кнопка, на которой может быть текст, совершает определенные действия при нажатии на нее. |
Entry | Виджет для ввода одной строчки текста. Эквивалент <input type="text"> в HTML. |
Text | Виджет для ввода большого текста. Эквивалент <textarea> в HTML. |
Frame | Прямоугольная область, что используется для группировки виджетов или для добавления расстояния между виджетами. |
В дальнейшем, мы на практике рассмотрим, как действует каждый из представленных выше виджетов. С более подробными списками виджетов Tkinter можете ознакомиться на страницах Basic Widgets и More Widgets. А пока рассмотрим подробнее виджет ярлыка Label.
Виджет Label — Отображение текста и картинок
Виджеты Label
используется для отображения текста или картинок. Текст на виджете Label
, не может редактироваться пользователем. Он только показывается. Как было показано в примере в начале данного руководства, виджет Label
можно создать через экземпляр класса Label
и передачу строки в параметр text
:
label = tk.Label(text=«Hello, Tkinter») |
Виджеты Label
отображают текст с установленным по умолчанию системным цветом и фоном. Обычно это черный и белый цвета. Следовательно, если в вашей операционной системе указаны иные цвета, именно их вы и увидите.
Изменить цвет текста и фона виджета Label
можно через параметры foreground
и background
:
label = tk.Label( text=«Привет, Tkinter!», foreground=«white», # Устанавливает белый текст background=«black» # Устанавливает черный фон ) |
Некоторые доступные цвета:
red
— красный;orange
— оранжевый;yellow
— желтый;green
— зеленый;blue
— синий;purple
— сиреневый.
Многие HTML-цвета имеют такое же название в Tkinter. Со списком доступных названий цветов можете ознакомиться здесь.
Если хотите подробнее разобраться в теме, особенно в системных цветах macOS и Windows, контролируемых текущей темой ОС, ознакомьтесь со страницей значений цветов.
Вы также можете указать цвет, используя шестнадцатеричные значения RGB такое часто используется в CSS для стилизации сайтов:
label = tk.Label(text=«Привет, Tkinter!», background=«#34A2FE») |
Теперь фон стал приятного голубого цвета. Шестнадцатеричные значения RGB, в отличие от названий цветов, закодированы, но это делает их более управляемыми. К счастью, доступны инструменты для простого и быстрого получения шестнадцатеричных кодов цветов.
Если вам не хочется регулярно вводить foreground
и background
, можете использовать сокращенные версии параметров — fg
и bg
. Они точно также отвечают за установку цвета текста и цвета фона.
label = tk.Label(text=«Привет, Tkinter!», fg=«white», bg=«black») |
Вы также можете управлять шириной и высотой ярлыка с помощью параметров width
и height
:
import tkinter as tk window = tk.Tk() label = tk.Label( text=«Привет, Tkinter!», fg=«white», bg=«black», width=20, height=20 ) label.pack() window.mainloop() |
В окне, ярлык будет выглядеть следующим образом:
Может показаться странным, что ярлык в окне не является квадратным, хотя параметр как ширины, так и высоты равен 20
. Все оттого, что ширина и высота измеряются в текстовых юнитах.
Горизонтальный текстовый юнит определен шириной символа "0"
, или цифрой ноль, в шрифте системы по умолчанию. Аналогичным образом один вертикальный текстовый юнит определен высотой символа "0"
.
На заметку: Tkinter использует текстовые юниты для измерения ширины и высоты вместо дюймов, сантиметров или пикселей, чтобы обеспечить согласованное поведение приложения на разных платформах.
Измерение юнитов шириной символа означает, что размер виджета относительно шрифта определяется по умолчанию на компьютере пользователя. Это обеспечивает правильное размещение текста на ярлыках и кнопках независимо от того, где запущено приложение.
Ярлыки отлично подходят для отображения текста, но через них пользователь не может вводить данные. Следующие три виджета позволяют пользователю вводить информацию.
Создание кнопки через виджет Button
Виджеты Button нужны для создания кликабельных кнопок. Их можно настроить таким образом, чтобы при нажатии вызывалась определенная функция. В следующей части урока, будет рассмотрено, как именно вызвать функцию при нажатии на кнопку. А пока займемся стилизацией виджета кнопки.
Существует много сходств между виджетами Button
и Label
. По сути кнопка — это просто ярлык, на который можно кликнуть. Для создания стилей виджетов ярлыка и кнопки также используются одинаковые аргументы.
К примеру, следующий код создает кнопку с синим фоном и желтым текстом. Также устанавливается ширина и высота с показателями в 25
и 5
текстовых юнит:
import tkinter as tk window = tk.Tk() button = tk.Button( text=«Нажми на меня!», width=25, height=5, bg=«blue», fg=«yellow», ) button.pack() window.mainloop() |
Готовая кнопка будет выглядеть следующим образом:
Неплохо! Следующие два виджета Entry
и Text
используются для сбора вводных данных от пользователя.
Виджет Entry — Однострочное текстовое поле
В случаях, когда требуется получить текстовую информацию от пользователя вроде адреса электронной почты, используется виджет Entry
. Он отображает небольшой текстовый бокс, куда пользователь может ввести текст.
Создание виджета Entry
практически ничем не отличается от процесса создания ярлыка и кнопки. К примеру, следующий код создает виджет с синим фоном и желтым текстом длиной в 50
текстовых юнит:
entry = tk.Entry(fg=«yellow», bg=«blue», width=50) |
В случае виджета однострочного текстового поля (Entry) интересен не процесс создания стиля, а то, как получить эти входные данные от пользователя. Есть три основные операции, что можно провести с виджетом однострочного текстового поля (Entry):
- Получение всего текста через
.get()
- Удаление текста через
.delete()
- Вставка нового текста через
.insert()
Для лучшего понимания принципа работы виджетов Entry
создадим один экземпляр элемента и попробуем ввести в него текст. Откройте оболочку Python и выполните следующие действия. Сначала импортируем tkinter
и создаем новое окно:
>>> import tkinter as tk >>> window = tk.Tk() |
Теперь создаем виджеты Label
и Entry
:
>>> label = tk.Label(text=«Имя») >>> entry = tk.Entry() |
Здесь ярлык указывает, что именно пользователь должен записать в виджете Entry
. Нет никаких ограничений для вводимых данных, это просто подсказка, что ввести нужно «Имя». Виджеты станут видимыми на окне после выполнения метода .pack()
для каждого из них:
>>> label.pack() >>> entry.pack() |
Результат выглядит следующим образом:
Обратите внимание, что в окне, виджет ярлыка автоматически центрирует над виджетом текстового поля. Это особенность разметки pack, о которой будет описано в следующих разделах.
На созданном в программе виджете мы ввели текст «Иван Иванов»:
Теперь в виджете текстового поля есть текст, только он еще не был отправлен в программу. Для получения текста и присваивания его значения переменной name
используется метод .get()
:
>>> name = entry.get() >>> name ‘Иван Иванов’ |
Текст также можно удалить, для этого используется метод .delete()
. Данный метод принимает аргумент, который является целым числом и сообщает Python, какой символ нужно удалить. К примеру, во фрагменте кода ниже показано, как через метод .delete(0)
можно удалить первый символ из текстового поля:
Теперь в виджете остался текст "ван Иванов"
:
Обратите внимание, что как и строки в Python, текст в виджете однострочного текстового поля индексируется, и начинается индексирование с 0
.
При необходимости удалить несколько символов из текстового поля нужно передать второй целочисленный аргумент в .delete()
, указав индекс символа, на котором процесс удаления должен завершиться. К примеру, следующий код удаляет первые четыре буквы из текстового поля:
Теперь остался только текст "Иванов"
:
Метод .delete()
работает по аналогии с методом строк slice()
для удаления части символов из строки. Первый аргумент определяет начальный индекс удаления, последний индекс указывает где именно процесс удаления должен остановиться.
Для удаления всего текста из текстового поля во втором аргументе метода .delete()
используется специальная константа tk.END
:
>>> entry.delete(0, tk.END) |
Теперь остался пустой текстовый бокс:
Вы также можете вставить текст в виджете однострочного текстового поля с помощью метода .insert()
:
>>> entry.insert(0, «Иванов») |
Теперь окно стало таким:
Первый аргумент сообщает методу .insert()
, куда вставить текст. Если в текстовом поле нет текста, новый текст будет всегда вставляться в начале виджета, и не важно, какое значение будет передано в качестве первого аргумента.
К примеру, при вызове .insert()
с первым аргументом 100
, а не 0
, как было сделано выше, вывод будет тем же.
В том случае, если текстовое поле уже содержит какой-то текст, тогда .insert()
вставить новый текст в указанную позицию и сдвинет существующий текст вправо:
>>> entry.insert(0, «Иван «) |
В виджете с текстом теперь значится "Иван Иванов"
:
Виджеты однострочного текстового поля отлично подходят для получения небольшого количества текста от пользователя, однако они отображают только одну строку текста, следовательно, для большого количества информации они не подойдут. Для таких случаев лучше использовать виджеты Text
.
Виджет Text — ввод большого текста в Tkinter
Виджеты Text
используются для ввода текста, как и виджеты Entry
. Разница в том, что Text
может содержать несколько строчек текста. С виджетом Text
пользователь может вводить целые параграфы или страницы текста. Как и в случае с виджетами Entry
, над виджетами Text
можно провести три основные операции:
- Получение текста через метод
.get()
- Удаление текста через метод
.delete()
- Вставка текста через метод
.insert()
Несмотря на то, что названия методов совпадают с теми, что используются в Entry
, процесс реализации несколько различен. Разберем пример создания виджета Text и посмотрим на деле, что он может делать.
На заметку: У вас все еще открыто предыдущее окно? Если это так, тогда закройте его, выполнив следующую команду:
Это также можно сделать вручную, просто нажав на кнопку «Закрыть».
В оболочке Python нужно создать новое пустое окно, а внутри нее с помощью метода .pack()
разместить текстовой виджет:
>>> import tkinter as tk >>> window = tk.Tk() >>> text_box = tk.Text() >>> text_box.pack() |
По умолчанию текстовые боксы значительно больше виджетов однострочного ввода текста Entry
. Созданное с помощью кода выше окно будет выглядеть следующим образом:
Для активации текстового бокса нажмите на любую точку внутри окна. Введите слово "Hello"
. Нажмите на клавиатуре кнопку Enter, после чего введите на второй строке слово "World"
. Окно будет выглядеть следующим образом:
Как и в случае с виджетами Entry
, вы можете получить текст их виджета Text
с помощью метода .get()
. Однако, вызов .get()
без аргументов не возвращает весь текст как это происходит с виджетами однострочного ввода текста Entry
. Появится исключение TypeError:
>>> text_box.get() Traceback (most recent call last): File «<pyshell#4>», line 1, in <module> text_box.get() TypeError: get() missing 1 required positional argument: ‘index1’ |
Метод .get()
для текстового виджета запрашивает хотя бы один аргумент. Вызов .get()
с единственным индексом возвращает один символ. Для получения нескольких символов требуется передать начальный и конечный индексы.
Индексы в виджетах Text
действуют иначе, чем в виджетах Entry
. Так как виджеты Text
могут получить несколько строк текста, индекс должен содержать следующие два пункта:
- Номер строки где находится символа;
- Позиция символа в строке.
Номера строк начинаются с 1
, а позиция символа с 0
. Для получения индекса создается строка формата "<line>.<char>"
, где <line>
заменяется номером строки, а <char>
номером символа. К примеру, "1.0"
означает первый символ на первой строке, а "2.3"
представляет четвертый символ на второй строке.
Используем индекс "1.0"
для получения первой буквы созданного ранее текстового бокса:
>>> text_box.get(«1.0») ‘H’ |
В слове "Hello"
5 букв, буква o
стоит под индексом 4
, так как отсчет символов начинается с 0
, и слово "Hello"
начинается с первой строки в текстовом боксе.
Как при слайсинге строк в Python, для получения целого слова "Hello"
из текстового бокса, конечный индекс должен быть на один больше последнего читаемого символа.
Таким образом, для получения слова "Hello"
из текстового бокса используется "1.0"
для первого индекса, и "1.5"
для второго индекса:
>>> text_box.get(«1.0», «1.5») ‘Hello’ |
Для получения "World"
на второй строке текстового бокса, измените номера строк каждого индекса на 2
:
>>> text_box.get(«2.0», «2.5») ‘World’ |
Для получения всего текста из текстового виджета установите индекс на "1.0"
и используйте специальную константу tk.END
для второго индекса:
>>> text_box.get(«1.0», tk.END) ‘HellonWorldn’ |
Обратите внимание, что текст, возвращаемый через метод .get()
, включает символы перехода на новую строку n
. Вы также можете увидеть в данном примере, что каждая строка в виджете Text
содержит в конце символ новой строки, включая последнюю строку текста в текстовом боксе.
Метод .delete()
используется для удаления символов из текстового виджета. Работает точно так же, как и метод .delete()
для виджетов Entry
. Есть два способа использования .delete()
:
- С одним аргументом;
- С двумя аргументами.
Используя вариант с одним аргументом, вы передаете индекс символа для удаления в .delete()
. К примеру, следующий код удаляет первый символ H
из текстового бокса:
>>> text_box.delete(«1.0») |
Теперь в первой строке текста значится "ello"
:
В версии с двумя аргументами передается два индекса для удаления группы символов, начиная с первого символа и заканчивая вторым, но не включая его.
К примеру, для удаления оставшейся части "ello"
из первой строки текстового бокса используются индексы "1.0"
и "1.4"
:
>>> text_box.delete(«1.0», «1.4») |
Обратите внимание, что текст из первой строки удалился, но осталась пустая строка, за которой следует слово World
на второй строке:
Хотя вам этого не видно, но на первой строке остался один символ — это символ новой строки n
. Вы можете сами убедиться в этом, вызвав метод .get()
:
>>> text_box.get(«1.0») ‘n’ |
При удалении данного символа оставшаяся часть содержимого текстового виджета сдвинется на строку вверх:
>>> text_box.delete(«1.0») |
Теперь слово "World"
переместилось на первую строку текстового виджета:
Попробуем очистить оставшуюся часть из текстового виджета. Установим "1.0"
в качестве стартового индекса и tk.END
в качестве второго индекса:
>>> text_box.delete(«1.0», tk.END) |
Теперь наш текстовый виджет совершенно пуст:
Вы также можете вставить текст в текстовый виджет с помощью метода .insert()
:
>>> text_box.insert(«1.0», «Hello») |
Метод вставляет слово "Hello"
в начало текстового виджета. Используется уже знакомый формат "<line>.<column>"
как и у метода .get()
для уточнения позиции вставки текста:
Проверьте, что произойдет при попытке вставить слово "World"
во вторую строчку:
>>> text_box.insert(«2.0», «World») |
Вместо вставки слова на вторую строку текст ставится в конце первой строки:
Если вы хотите поставить текст на новую строку, тогда понадобится вставить символ новой строки n
вручную:
>>> text_box.insert(«2.0», «nWorld») |
Теперь слово "World"
находится на второй строке текстового виджета:
Метод .insert()
делает следующие две вещи:
- Вставляет текст в указанной позиции, если в этой позиции или после неё уже находится текст;
- Добавляет текст в указанную строку, если номер символа превышает индекс последнего символа в текстовом боксе.
Обычно нецелесообразно пытаться отследить индекс последнего символа. Лучший способ вставить текст в конец виджета Text
— передать tk.END
как первый параметр в методе .insert()
:
text_box.insert(tk.END, «Вставь меня в самом конце!») |
Не забудьте включить символ новой строки (n)
в начале текста, если вы хотите расположить его на новой строке:
text_box.insert(tk.END, «nВставь меня в новую строку!») |
Виджеты Label
, Button
, Entry
и Text
являются только небольшой частью виджетов, доступных в Tkinter. Среди прочих виджетов есть чекбоксы, радио кнопки, скролл бары и прогресс бары.
Использование виджета Frame в Tkinter
В данном руководстве мы рассмотрим только пять виджетов. Это описанные ранее четыре виджета плюс виджет рамки Frame
. Виджеты рамок важны для организации макета виджетов в приложении.
Прежде чем углубляться в детали макетов виджетов более подробно рассмотрим, как работает виджет рамки, и как вы можете вставить в них другие виджеты. Следующий скрипт создает пустой виджет рамки и добавляет его на главное окно приложения:
import tkinter as tk window = tk.Tk() frame = tk.Frame() frame.pack() window.mainloop() |
Метод frame.pack()
помещает рамку в окно, таким образом размер окна становится таким маленьким, каким он может быть для того, чтобы поместился рамку. При запуске скрипта выше будет получен крайне скучный вывод:
Пустой виджет рамки практически невидим.
Рамки лучше всего рассматривать как контейнеры для других виджетов.
Вы можете вставить любой виджет в рамку, установив атрибут master
данному виджету:
frame = tk.Frame() label = tk.Label(master=frame) |
Чтобы посмотреть, как это работает, напишем скрипт для создания двух виджетов Frame
под названиями frame_a
и frame_b
. В данном скрипте frame_a
содержит ярлык с текстом "I'm in Frame A"
, а frame_b
содержит ярлык с текстом "I'm in Frame B"
. Вот как это можно сделать:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import tkinter as tk window = tk.Tk() frame_a = tk.Frame() frame_b = tk.Frame() label_a = tk.Label(master=frame_a, text=«I’m in Frame A») label_a.pack() label_b = tk.Label(master=frame_b, text=«I’m in Frame B») label_b.pack() frame_a.pack() frame_b.pack() window.mainloop() |
Обратите внимание, что рамка frame_a
помещается в окно перед рамкой frame_b
. Открывающееся окно показывает ярлык в рамке frame_a
над ярлыком в рамке frame_b
:
Теперь посмотрим, что произойдет при изменении порядка вставки frame_a.pack()
и frame_b.pack()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import tkinter as tk window = tk.Tk() frame_a = tk.Frame() label_a = tk.Label(master=frame_a, text=«I’m in Frame A») label_a.pack() frame_b = tk.Frame() label_b = tk.Label(master=frame_b, text=«I’m in Frame B») label_b.pack() # Вставка рамок в окне поменялись местами. frame_b.pack() frame_a.pack() window.mainloop() |
Вывод выглядит следующим образом:
Теперь ярлык label_b
сверху. Так как ярлык label_b
назначен к рамке frame_b
, он перемещается, куда позиционируется рамка frame_b
.
У всех четырех рассмотренных типов виджетов — Label
, Button
, Entry
и Text
— есть атрибут master
, который устанавливается при их создании. Таким образом, вы можете управлять тем, к какой именно рамки назначен виджет.
Виджеты Frame
отлично подходят для логической организации других виджетов в окне приложения. Связанные виджеты могут быть назначены одной и той же рамки, так что, если рамка когда-либо перемещается в окне, связанные виджеты перемещаются вместе с ней.
В дополнение к логической группировке ваших виджетов, рамки могут немного улучшить внешний вид вашего приложения. Дальше будет показано, как менять стиль рамок.
Атрибут relief в Tkinter — Меняем стиль рамки
Рамки могут менять свой стиль с помощью атрибута relief
, который создает границу вокруг рамки. Можно присвоить relief
любое из следующих значений:
tk.FLAT
: Никакого эффекта рамки (по умолчанию);tk.SUNKEN
: Создается эффект углубления элемента;tk.RAISED
: Создается эффект выпуклости элемента;tk.GROOVE
: Создается эффект врезанной в текстуру рамки, своего рода выемки;tk.RIDGE
: Создается эффект выпуклой выемки.
Для применения эффекта рамки нужно установить значение атрибута borderwidth
выше, чем 1
. Данный атрибут корректирует ширину рамки в пикселях. Лучший способ понять, как выглядит каждый эффект — проверить на практике.
Вот скрипт, который помещает пять рамок в окно, где каждая из которых имеет свое значение аргумента relief
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import tkinter as tk border_effects = { «flat»: tk.FLAT, «sunken»: tk.SUNKEN, «raised»: tk.RAISED, «groove»: tk.GROOVE, «ridge»: tk.RIDGE, } window = tk.Tk() for relief_name, relief in border_effects.items(): frame = tk.Frame(master=window, relief=relief, borderwidth=5) frame.pack(side=tk.LEFT) label = tk.Label(master=frame, text=relief_name) label.pack() window.mainloop() |
Разбор скрипта по строкам кода:
- Строки с 3 по 9 создают словарь, ключами которого являются названия различных эффектов от
relief
, доступных в Tkinter. Значения являются соответствующими объектами Tkinter. Этот словарь назначен переменнойborder_effects
- Строка 13 запускает цикл for для каждого элемента в словаре
border_effects
- Строка 14 создает новый виджет
Frame
и назначает его объектуwindow
. Атрибутrelief
установлен на соответствующий элемент рельефа в словареborder_effects
, а атрибутborder
установлен на5
пикселей, чтобы эффект был видимым - Строка 15 помещает виджет рамки в окно с помощью метода
.pack()
. Ключевое словоside
указывает Tkinter, где поместить поместить рамку. Подробнее о том, как это работает, вы узнаете в следующем разделе. - Строки 16 и 17 создаем виджет текстового ярлыка для отображения названия рельефа и помещаем его в только что созданную рамку.
Окно, созданное вышеуказанным скриптом, выглядит следующим образом:
На данной картинке представлены следующие эффекты:
- tk.FLAT создает простую рамку без видимой границы;
- tk.SUNKEN добавляет границу, которая создает эффект, будто элемент провалился в окне;
- tk.RAISED создает рамке границу в виде эффекта выпуклости;
- tk.GROOVE добавляет эффект врезанной, будто утопающей в текстуру, рамки;
- tk.RIDGE создает эффект, будто врезанной с другой стороны выпуклой рамки.
Данные эффекты могут сделать ваше приложение на Tkinter более интересным с визуальной точки зрения.
Правила именования виджетов в Tkinter
При создании виджета можно дать ему любое имя при условии, что данное имя уже не зарегистрировано самим Python, вроде with
, for
, range
и т.д.
Обычно хорошей идеей является включение имени класса виджета в имя переменной, которую вы назначаете экземпляру виджета. Например, если виджет Label
используется для отображения имени пользователя, вы можете назвать виджет label_user_name
. Виджет Entry
, используемый для определения возраста пользователя, может называться entry_age
.
Когда вы включаете имя класса виджета в имя переменной, вы помогаете себе (и всем, кому необходимо прочитать ваш код), чтобы понять, к какому типу виджетов относится имя переменной.
Однако использование полного имени класса виджета может привести к длинным именам переменных, поэтому вы можете захотеть использовать сокращение для отсылки на каждый тип виджета. В оставшейся части этого урока будем использовать следующие сокращенные префиксы для именования виджетов:
Класс виджета | Префикс названия переменной | Пример |
---|---|---|
Label | lbl | lbl_name |
Button | btn | btn_submit |
Entry | ent | ent_age |
Text | txt | txt_notes |
Frame | frm | frm_address |
В этом разделе мы узнали, как создать окно, использовать виджеты и работать с рамками. На этом этапе нам удалось создать несколько простых окон, которые отображают сообщения, но это еще не полноценное приложение.
В следующем разделе мы познакомимся с управлением макетом приложений с помощью мощных менеджеров геометрии от Tkinter.
Задание #2 — Создать текстовое поле и вставить в нее текст
Попробуйте выполнить данную задачку, чтобы убедиться, что вы действительно поняли принцип работы описанных ранее виджетов.
Задание: Создать однострочное текстовое поле и вставить на нее какой-то текст.
- Напишите скрипт для отображения виджета однострочного текстового поля
Entry
шириной в 40 текстовых юнитов с белым фоном и черным текстом; - Используйте метод
.insert()
для вставки текста:"What is your name?"
.
Результат должен выглядеть следующим образом:
Попробуйте выполнить задание самостоятельно.
Ниже представлен вариант кода для выполнения данного задания. В следующем варианте для установки фона и цвета шрифта текстового виджета, используются параметры bg
и fg
. Помните, что ваша программа может отличаться от нашей, у каждого разработчика свой стиль программирования.
Код с решением задачи #2
import tkinter as tk window = tk.Tk() entry = tk.Entry(width=40, bg=«white», fg=«black») entry.pack() entry.insert(0, «What is your name?») window.mainloop() |
Это хорошее решение, цвет фона и цвет шрифта для виджета однострочного текстового поля Entry
указываются довольно просто.
В большинстве систем по умолчанию цвет фона для виджета Entry
— белый, а цвет содержимого — черный. Таким образом, вы можете создать то же самое окно, не уточняя при этом параметры bg
и fg
:
Измененный код с решением задачи #2
import tkinter as tk window = tk.Tk() entry = tk.Entry(width=40) entry.pack() entry.insert(0, «What is your name?») window.mainloop() |
Помните, что ваш код может выглядеть иначе. Когда будете готовы, переходите к следующим разделам руководства.
Настройка макета приложения через менеджеры геометрии
До данного момента мы добавляли виджеты на окно с помощью метода .pack()
, однако что именно делает данный метод нам пока неизвестно.
Давайте все проясним. Макет приложения в Tkinter управляется через менеджеры геометрии. Одним из менеджеров геометрии является .pack()
. Помимо него в Tkinter есть еще двое таких менеджеров:
.place()
.grid()
Каждое окно и рамка в приложении может использовать только один менеджер геометрии. Однако разные рамки могут использовать разные менеджеры геометрии, даже если они назначены окну или рамики, что использует другой менеджер геометрии. Начнем с более подробного разбора менеджера .pack()
.
Менеджер геометрии pack() в Tkinter
Менеджер .pack()
используется для размещения виджетов на рамку или на окне приложения в определенном порядке использует алгоритм упаковки. Для заданного виджета у алгоритма упаковки есть два основных этапа:
- Расчет прямоугольной области, называемой участком. Размер области подходит для вмещения виджета, а оставшаяся ширина (или высота) окна заполняется пустым пространством;
- Центрирование виджета в участке, если не указано другое местоположение в окне.
Менеджер геометрии .pack()
является мощным инструментом, но его может быть трудно визуализировать. Лучший способ понять .pack()
— это разобрать примеры.
Посмотрите, что происходит при размещении трех виджетов ярлыков с текстом в рамку через менеджер .pack()
:
import tkinter as tk window = tk.Tk() frame1 = tk.Frame(master=window, width=100, height=100, bg=«red») frame1.pack() frame2 = tk.Frame(master=window, width=50, height=50, bg=«yellow») frame2.pack() frame3 = tk.Frame(master=window, width=25, height=25, bg=«blue») frame3.pack() window.mainloop() |
По умолчанию .pack()
помещает каждую рамку друг под другом в том порядке, в котором они добавлены на окно приложения:
Каждая рамка находится на самой верхней доступной позиции. Красный в верхней части окна, желтый находится чуть ниже красного, а синий чуть ниже желтого.
Есть три невидимых участка в каждой рамки. Ширина каждого участка совпадает с шириной окна, а высота с высотой рамки внутри. Поскольку, при каждом вызове метода .pack()
для каждой рамки не было указано никакой точки привязки, все они центрированы внутри своих участков. Вот почему каждая рамка находится в центре окна.
Менеджер .pack()
принимает некоторые ключевые аргументы для более точной настройки размещения виджетов. К примеру, можно установить ключевой аргумент fill
для уточнения в какое направление рамки будут пополняться. Доступная опция tk.X
для горизонтального направления, tk.Y
для вертикального направления и tk.BOTH
для обоих. Далее представлен код для горизонтального заполнения окна тремя рамками:
import tkinter as tk window = tk.Tk() frame1 = tk.Frame(master=window, height=100, bg=«red») frame1.pack(fill=tk.X) frame2 = tk.Frame(master=window, height=50, bg=«yellow») frame2.pack(fill=tk.X) frame3 = tk.Frame(master=window, height=25, bg=«blue») frame3.pack(fill=tk.X) window.mainloop() |
Обратите внимание, что для виджета рамки ширина width
не установлена. Аргумент width
больше не требуется, так как каждая рамка задействует .pack()
для горизонтального заполнения, переписывая любой индивидуальный параметр ширины.
Результат вышеуказанного скрипта будет выглядеть следующим образом:
Одна из приятных особенностей заполнения окна с помощью .pack()
заключается в том, что содержимое реагирует на изменение размера окна. Попробуйте расширить окно, созданное предыдущим скриптом, чтобы увидеть, как это работает. Когда вы расширяете окно, ширина трех рамок внутри также увеличивается, заполняя окно:
Обратите внимание, что виджеты рамок не растягиваются в вертикальном направлении.
Аргумент side
от метода .pack()
уточняет, на какую сторону окна виджет должен размещаться. Доступные варианты:
tk.TOP
сверху;tk.BOTTOM
снизу;tk.LEFT
слева;tk.RIGHT
справа.
В случае, если аргумент side
не указан, тогда метод .pack()
автоматически использует tk.TOP
и ставит новые виджеты в верхнюю часть окна, или в самую верхнюю часть окна, которая еще не занята виджетом. К примеру, следующий скрипт размещает три рамки рядом друг с другом слева направо и расширяет каждую рамку, чтобы заполнить окно по вертикали:
import tkinter as tk window = tk.Tk() frame1 = tk.Frame(master=window, width=200, height=100, bg=«red») frame1.pack(fill=tk.Y, side=tk.LEFT) frame2 = tk.Frame(master=window, width=100, bg=«yellow») frame2.pack(fill=tk.Y, side=tk.LEFT) frame3 = tk.Frame(master=window, width=50, bg=«blue») frame3.pack(fill=tk.Y, side=tk.LEFT) window.mainloop() |
Теперь нужно указать аргумент height
как минимум для одной рамки, чтобы назначить окну определенную высоту.
Полученное окно выглядит следующим образом:
При установке аргумента fill=tk.X
рамки адаптируются при горизонтальном изменении размера окна, а при указании аргумента fill=tk.Y
они адаптируются при изменении размера окна по вертикали:
Для того чтобы сделать макет по-настоящему адаптированным, можно установить начальный размер фреймов, используя атрибуты width
и height
. Затем нужно установить значение аргумента fill
от метода .pack()
на tk.BOTH
, а также установить значение аргумента expand
на True
:
import tkinter as tk window = tk.Tk() frame1 = tk.Frame(master=window, width=200, height=100, bg=«red») frame1.pack(fill=tk.BOTH, side=tk.LEFT, expand=True) frame2 = tk.Frame(master=window, width=100, bg=«yellow») frame2.pack(fill=tk.BOTH, side=tk.LEFT, expand=True) frame3 = tk.Frame(master=window, width=50, bg=«blue») frame3.pack(fill=tk.BOTH, side=tk.LEFT, expand=True) window.mainloop() |
При запуске вышеуказанного кода результатом будет окно, что поначалу будет выглядеть как и предыдущий пример. Разница в том, что теперь можно менять размер окна в любом направлении, и рамки будут соответственно адаптироваться при изменении размеров окна:
Вышло неплохо!
Менеджер геометрии place() в Tkinter
Для управления точным местом расположения виджета в окне или в рамке используется менеджер .place()
. Вы должны указать два ключевых аргумента x
и y
, которые определяют координаты x
и y
для верхнего левого угла виджета. Аргументы x
и y
измеряются в пикселях, а не в текстовых юнитах.
Имейте в виду, что начало координат (где x
и y
равны 0
) — это верхний левый угол рамки или окна. Таким образом, вы можете рассматривать аргумент y
в методе .place()
как количество пикселей в верхней части окна, а аргумент x
— в качестве количества пикселей в левой части окна.
Вот пример того, как работает менеджер геометрии .place()
:
import tkinter as tk window = tk.Tk() frame = tk.Frame(master=window, width=150, height=150) frame.pack() label1 = tk.Label(master=frame, text=«I’m at (0, 0)», bg=«red») label1.place(x=0, y=0) label2 = tk.Label(master=frame, text=«I’m at (75, 75)», bg=«yellow») label2.place(x=75, y=75) window.mainloop() |
Разберем код:
- Строки 5 и 6 создают новый виджет рамки
Frame
под названиемframe1
, его ширина 150 пикселей и высота также 150 пикселей, и упаковывают его в окно с помощью.pack()
; - Строки 8 и 9 создают новый ярлык с текстом под названием
label1
с желтым фоном и помещает его в рамкуframe1
на позицию(0, 0)
; - Строки 11 и 12 создают второй ярлык с текстом под названием
label2
на красном фоне и помещают его в рамкуframe1
на позицию(75, 75)
.
Вот окно, которое создалась при выполнении данного кода:
Менеджер геометрии .place()
используется не очень часто. У него есть два значимых недостатка:
- Через метод
.place()
макет сложно настраивать, особенно в тех случаях, когда у приложений много виджетов; - Макеты, созданные при помощи менеджера
.place()
, не адаптируются. Они не меняются вместе с изменением размера главного окна.
Одной из основных проблем при разработке кроссплатформенного графического интерфейса является создание макетов, которые хорошо выглядят независимо от того, на какой платформе они просматриваются.
В таком случае менеджер геометрии .place()
— плохой выбор для создания адаптивных и кроссплатформенных макетов.
Однако это не значит, что нужно отказаться от использования менеджера .place()
!
В некоторых случаях это оптимальный выбор. Например, если вы создаете графический интерфейс для географической карты, то .place()
прекрасно подойдет. Он обеспечит размещение виджетов на правильном расстоянии друг от друга на карте.
Как правило, лучше использовать менеджер .pack()
, а не .place()
. Тем не менее, и у .pack()
есть определенные недостатки. Расположение виджетов зависит от порядка, в котором вызывается метод .pack()
, поэтому может быть сложно модифицировать существующие приложения без полного понимания кода, управляющего макетом. Менеджер геометрии .grid()
решает многие из этих проблем.
Поговорим об этом в следующем разделе.
Менеджер геометрии grid() в Tkinter
Самым популярным менеджером геометрии в Tkinter является .grid()
. Он обладает всей мощностью .pack()
, будучи намного более простым в использовании.
Менеджер .grid()
работает путем разделения окна или рамки на строки и столбцы (на сетку). Вы указываете местоположение виджета, вызывая метод .grid()
и передавая индексы row
и column
(строки и столбца) в ключевые аргументы строки и столбца соответственно.
Индексы строк и столбцов начинаются с 0
, поэтому индекс строки 1
и индекс столбца 2
указывают методу .grid()
, что виджет нужно разместить в третьем столбце второй строки.
Следующий скрипт создает сетку из рамок 3 × 3
с находящимися в них ярлыками с текстом:
import tkinter as tk window = tk.Tk() for i in range(3): for j in range(3): frame = tk.Frame( master=window, relief=tk.RAISED, borderwidth=1 ) frame.grid(row=i, column=j) label = tk.Label(master=frame, text=f«Row {i}nColumn {j}») label.pack() window.mainloop() |
Результат выглядит следующим образом:
В данном примере использовались два менеджера геометрии. Каждая рамка привязана к определенному окну через менеджер геометрии grid()
:
import tkinter as tk window = tk.Tk() for i in range(3): for j in range(3): frame = tk.Frame( master=window, relief=tk.RAISED, borderwidth=1 ) frame.grid(row=i, column=j) label = tk.Label(master=frame, text=f«Row {i}nColumn {j}») label.pack() window.mainloop() |
Каждый ярлык с текстом привязан к определенной рамки через менеджер .pack()
:
import tkinter as tk window = tk.Tk() for i in range(3): for j in range(3): frame = tk.Frame( master=window, relief=tk.RAISED, borderwidth=1 ) frame.grid(row=i, column=j) label = tk.Label(master=frame, text=f«Row {i}nColumn {j}») label.pack() window.mainloop() |
Важно понимать, что метод .grid()
вызывается для каждого объекта рамки, но менеджер геометрии применяется к окну. Аналогично, расположение каждой рамки контролируется менеджером геометрии .pack()
.
Рамки в предыдущем примере расположены рядом друг с другом. Чтобы добавить пространство вокруг каждой рамки, вы можете установить отступ для каждой ячейки в сетке.
Отступ, или padding — это просто пустое пространство, которое окружает виджет и визуально отделяет его от его содержимого.
Есть два вида отступов — внешние и внутренние. Внешнее отступы добавляют пространство вокруг ячейки сетки. Управление осуществляется через два ключевые аргумента метода .grid()
:
padx
добавляет отступ в горизонтальном направлении;pady
добавляет отступы в вертикальном направлении.
Аргументы padx
и pady
измеряются в пикселях, а не в текстовых юнитах, поэтому установка их обоих на одно и то же значение создаст одинаковое количество отступов в обоих направлениях. Попробуем добавить отступы вокруг рамок из предыдущего примера:
import tkinter as tk window = tk.Tk() for i in range(3): for j in range(3): frame = tk.Frame( master=window, relief=tk.RAISED, borderwidth=1 ) frame.grid(row=i, column=j, padx=5, pady=5) label = tk.Label(master=frame, text=f«Row {i}nColumn {j}») label.pack() window.mainloop() |
Вот результат:
У менеджера геометрии .pack()
также есть параметры padx
и pady
. Следующий код почти идентичен предыдущему коду, за исключением того, что добавляется 5 пикселей дополнительного отступа вокруг каждого ярлыка с текстом в направлениях x
и y
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import tkinter as tk window = tk.Tk() for i in range(3): for j in range(3): frame = tk.Frame( master=window, relief=tk.RAISED, borderwidth=1 ) frame.grid(row=i, column=j, padx=5, pady=5) label = tk.Label(master=frame, text=f«Row {i}nColumn {j}») label.pack(padx=5, pady=5) window.mainloop() |
Дополнительные отступы вокруг ярлыков с текстом немного расширяют место для каждой ячейки в сетке между рамкой Frame
и текстом на ярлыке Label
:
Выглядит неплохо! Однако при попытке расширить окно в каком бы то ни было направлении можно заметить, что макет не адаптируется:
При расширении окна сетка с виджетами остается в верхнем левом углу.
Можно настроить так, чтобы строки и столбы сетки будут реагировать на изменение размера окна с помощью метода .columnconfigure()
и .rowconfigure()
для объекта окна приложения. Помните, что сетка привязана к окну, даже если вы вызываете метод .grid()
для каждой рамки. Метод .columnconfigure()
и .rowconfigure()
принимают три важных аргумента:
- Индекс столбца или строки сетки, которого нужно настроить (или список индексов для настройки нескольких строк или столбцов одновременно);
- Ключевой аргумент под названием
weight
, который определяет, как столбец или строка должны реагировать на изменение размера окна относительно других столбцов и строк; - Ключевой аргумент под названием
minsize
, который устанавливает минимальный размер высоты строки или ширины столбца в пикселях.
Аргумент weight
по умолчанию равен 0
. Это означает, что столбец или строка не расширяются при изменении размера окна. Если каждому столбцу и строке присвоен weight=1
, то все они будут меняться одинаково. Если вес (weight) одного столбца 1, а у другого 2, то второй столбец расширяется вдвое быстрее первого. Настроим предыдущий скрипт для лучшей обработки изменения размера окна:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import tkinter as tk window = tk.Tk() for i in range(3): window.columnconfigure(i, weight=1, minsize=75) window.rowconfigure(i, weight=1, minsize=50) for j in range(0, 3): frame = tk.Frame( master=window, relief=tk.RAISED, borderwidth=1 ) frame.grid(row=i, column=j, padx=5, pady=5) label = tk.Label(master=frame, text=f«Row {i}nColumn {j}») label.pack(padx=5, pady=5) window.mainloop() |
Метод .columnconfigure()
и .rowconfigure()
помещаются в тело внешнего цикла for. Можно точно настроить каждый столбец и строку за пределами цикла for, однако для этого нужно будет написать дополнительные шесть строк кода.
В каждой итерации цикла i
-ые столбцы и строки настраиваются таким образом, чтобы значение их weight
было равно 1
. Это является гарантией того, что каждая строка и столбец расширяются с одинаковой скоростью при изменении размера окна. Аргумент minsize
имеет значение 75
для каждого столбца и 50
для каждой строки. Это гарантирует, что ярлык с текстом всегда отображает свой текст без обрезания каких-либо символов, даже если размер окна очень мал.
Результатом является макет сетки, который плавно расширяется и сжимается при изменении размера окна:
Попробуйте самим изменить размер окна. Поэкспериментируйте с параметрами weight
и minsize
, чтобы посмотреть, как они влияют на сетку.
По умолчанию виджеты центрируются в своих ячейках сетки. К примеру, следующий код создает два ярлыка с текстом и помещает их в сетку с одним столбцом и двумя строками:
import tkinter as tk window = tk.Tk() window.columnconfigure(0, minsize=250) window.rowconfigure([0, 1], minsize=100) label1 = tk.Label(text=«A») label1.grid(row=0, column=0) label2 = tk.Label(text=«B») label2.grid(row=1, column=0) window.mainloop() |
Ширина каждой ячейка сетки 250
пикселей, высота 100
пикселей. Ярлыки с текстом помещаются в центре каждой ячейки, как показано в следующей фигуре:
Вы можете поменять расположение каждого ярлыка внутри ячейки сетки, используя параметр sticky
. Параметр sticky принимает строку, что содержит одну или несколько из следующих букв:
- «n» или «N» — Север — выравнивает по верхней центральной части ячейки;
- «e» или «E» — Запад — выравнивает по правой центральной части ячейки;
- «s» или «S» — Юг — выравнивает по нижней центральной части ячейки;
- «w» или «W» — Восток — выравнивает по левой центральной части ячейки.
Буквы «n», «s», «e» и «w» идут по траектории с севера, на юг, затем восток и запад. Установка параметра sticky
со значением «n» для обоих ярлыков из предыдущего кода позиционируют каждый ярлык с текстом в верхнюю центральную ячейку сетки:
import tkinter as tk window = tk.Tk() window.columnconfigure(0, minsize=250) window.rowconfigure([0, 1], minsize=100) label1 = tk.Label(text=«A») label1.grid(row=0, column=0, sticky=«n») label2 = tk.Label(text=«B») label2.grid(row=1, column=0, sticky=«n») window.mainloop() |
Результат:
Можно комбинировать несколько букв в одной строке для позиционирования каждого ярлыка в углу его ячейки из сетки:
import tkinter as tk window = tk.Tk() window.columnconfigure(0, minsize=250) window.rowconfigure([0, 1], minsize=100) label1 = tk.Label(text=«A») label1.grid(row=0, column=0, sticky=«ne») label2 = tk.Label(text=«B») label2.grid(row=1, column=0, sticky=«sw») window.mainloop() |
В данном примере параметр sticky
ярлыка label1
настроен на "ne"
, который позиционируется ярлык в верхний правый угол ячейки сетки. Ярлык label2
позиционируется в нижнем левом углу, указывая "sw"
в аргументе sticky
.
Вот как будет выглядеть окно:
Когда виджет позиционируется через sticky
, размера самого виджета достаточно для размещения любого текста и другого содержимого внутри него. Он не заполнить всю ячейку сетки. Для заполнения всей сетки можно указать "ns"
, заставив виджет заполнить ячейку в вертикальном направлении, или "ew"
для заполнения ячейки в горизонтальном направлении. Для заполнения всей ячейки в sticky
требуется указать "nsew"
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import tkinter as tk window = tk.Tk() window.rowconfigure(0, minsize=50) window.columnconfigure([0, 1, 2, 3], minsize=50) label1 = tk.Label(text=«1», bg=«black», fg=«white») label2 = tk.Label(text=«2», bg=«black», fg=«white») label3 = tk.Label(text=«3», bg=«black», fg=«white») label4 = tk.Label(text=«4», bg=«black», fg=«white») label1.grid(row=0, column=0) label2.grid(row=0, column=1, sticky=«ew») label3.grid(row=0, column=2, sticky=«ns») label4.grid(row=0, column=3, sticky=«nsew») window.mainloop() |
Результат выглядит следующим образом:
Приведенный выше пример демонстрирует то, что параметр sticky
от менеджера геометрии .grid()
может использоваться для достижения тех же эффектов, что и параметр fill
от менеджера геометрии .pack()
. Параллели между параметрами sticky
и fill
представлены в следующей таблице:
Метод grid() | Метод pack() |
sticky="ns" |
fill=tk.Y |
sticky="ew" |
fill=tk.X |
sticky="nsew" |
fill=tk.BOTH |
Метод .grid()
является довольно мощным менеджером геометрии. Зачастую его проще понять, чем менеджер .pack()
. Он также универсальнее, нежели менеджер .place()
. При создании новых приложений в Tkinter, в качестве основного менеджера геометрии лучше рассматривать .grid()
.
На заметку:
.grid()
очень гибок в плане управления. Например, вы можете настроить ячейки на несколько строк и столбцов. Для получения дополнительной информации просмотрите раздел Grid Geometry Manager.
Теперь вы обладаете основными знаниями о менеджерах геометрии и их роли при работе с графическим фреймворком Tkinter. Далее мы попробуем присвоить действия кнопкам, тем самым несколько оживив приложение.
Задание #3 Создайте анкету с контактными данными клиента
Ниже дано еще одно задание для проверки понимания всего изученного.
Задание: Создать форму для ввода полного адреса клиента.
Ниже представлено изображение формы для ввода полного домашнего адреса клиента, которая была создана через Tkinter.
Вам нужно написать скрипт для создания такого же окна, что на картинке выше. Используйте любые менеджеры геометрии.
Ниже представлен наш вариант кода. Есть много разных способов выполнить данное задание. Если ваш вариант воспроизводит такое же окно как на картинке, то поздравляем! Вы справились! Ниже можете также ознакомиться с двумя вариантами кода, где используется менеджер .grid()
.
В следующем варианте создаются виджеты ярлыка с текстом и однострочное поле для ввода текста для каждого поля с желаемыми данными:
Полный код с решением задачи #3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
import tkinter as tk # Создается новое окно с заголовком «Введите домашний адрес» window = tk.Tk() window.title(«Введите домашний адрес») # Создается новая рамка `frm_form` для ярлыков с текстом и # Однострочных полей для ввода информации об адресе. frm_form = tk.Frame(relief=tk.SUNKEN, borderwidth=3) # Помещает рамку в окно приложения. frm_form.pack() # Создает ярлык и текстовок поле для ввода имени. lbl_first_name = tk.Label(master=frm_form, text=«Имя:») ent_first_name = tk.Entry(master=frm_form, width=50) # Использует менеджер геометрии grid для размещения ярлыка и # однострочного поля для ввода текста в первый и второй столбец # первой строки сетки. lbl_first_name.grid(row=0, column=0, sticky=«e») ent_first_name.grid(row=0, column=1) # Создает ярлык и текстовок поле для ввода фамилии. lbl_last_name = tk.Label(master=frm_form, text=«Фамилия:») ent_last_name = tk.Entry(master=frm_form, width=50) # Размещает виджеты на вторую строку сетки lbl_last_name.grid(row=1, column=0, sticky=«e») ent_last_name.grid(row=1, column=1) # Создает ярлык и текстовок поле для ввода первого адреса. lbl_address1 = tk.Label(master=frm_form, text=«Адрес 1:») ent_address1 = tk.Entry(master=frm_form, width=50) # Размещает виджеты на третьей строке сетки. lbl_address1.grid(row=2, column=0, sticky=«e») ent_address1.grid(row=2, column=1) # Создает ярлык и текстовок поле для ввода второго адреса. lbl_address2 = tk.Label(master=frm_form, text=«Адрес 2:») ent_address2 = tk.Entry(master=frm_form, width=50) # Размещает виджеты на четвертой строке сетки. lbl_address2.grid(row=3, column=0, sticky=tk.E) ent_address2.grid(row=3, column=1) # Создает ярлык и текстовок поле для ввода города. lbl_city = tk.Label(master=frm_form, text=«Город:») ent_city = tk.Entry(master=frm_form, width=50) # Размещает виджеты на пятой строке сетки. lbl_city.grid(row=4, column=0, sticky=tk.E) ent_city.grid(row=4, column=1) # Создает ярлык и текстовок поле для ввода региона. lbl_state = tk.Label(master=frm_form, text=«Регион:») ent_state = tk.Entry(master=frm_form, width=50) # Размещает виджеты на шестой строке сетки. lbl_state.grid(row=5, column=0, sticky=tk.E) ent_state.grid(row=5, column=1) # Создает ярлык и текстовок поле для ввода почтового индекса lbl_postal_code = tk.Label(master=frm_form, text=«Почтовый индекс:») ent_postal_code = tk.Entry(master=frm_form, width=50) # Размещает виджеты на седьмой строке сетки. lbl_postal_code.grid(row=6, column=0, sticky=tk.E) ent_postal_code.grid(row=6, column=1) # Создает ярлык и текстовок поле для ввода страны. lbl_country = tk.Label(master=frm_form, text=«Страна:») ent_country = tk.Entry(master=frm_form, width=50) # Размещает виджеты на восьмой строке сетки. lbl_country.grid(row=7, column=0, sticky=tk.E) ent_country.grid(row=7, column=1) # Создает новую рамку `frm_buttons` для размещения # кнопок «Отправить» и «Очистить». Данная рамка заполняет # все окно в горизонтальном направлении с # отступами в 5 пикселей горизонтально и вертикально. frm_buttons = tk.Frame() frm_buttons.pack(fill=tk.X, ipadx=5, ipady=5) # Создает кнопку «Отправить» и размещает ее # справа от рамки `frm_buttons`. btn_submit = tk.Button(master=frm_buttons, text=«Отправить») btn_submit.pack(side=tk.RIGHT, padx=10, ipadx=10) # Создает кнопку «Очистить» и размещает ее # справа от рамки `frm_buttons`. btn_clear = tk.Button(master=frm_buttons, text=«Очистить») btn_clear.pack(side=tk.RIGHT, ipadx=10) # Запуск приложения. window.mainloop() |
Это довольно неплохое решение. Оно немного длинное, зато понятное. При желании что-то изменить сразу ясно, где это можно сделать.
Есть и более короткий вариант решения. Учитывая, что у каждого текстового поля одинаковая ширина width
, понадобится только указать текст для ярлыков:
Обновленный код с решением задачи #3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
import tkinter as tk # Создается новое окно с заголовком «Введите домашний адрес». window = tk.Tk() window.title(«Address Entry Form») # Создается новая рамка `frm_form` для ярлыков с текстом и # Однострочных полей для ввода информации об адресе. frm_form = tk.Frame(relief=tk.SUNKEN, borderwidth=3) # Помещает рамку на окно приложения. frm_form.pack() # Список ярлыков полей. labels = [ «Имя:», «Фамилия:», «Адрес 1:», «Адрес 2:», «Город:», «Регион:», «Почтовый индекс:», «Страна:», ] # Цикл для списка ярлыков полей. for idx, text in enumerate(labels): # Создает ярлык с текстом из списка ярлыков. label = tk.Label(master=frm_form, text=text) # Создает текстовое поле которая соответствует ярлыку. entry = tk.Entry(master=frm_form, width=50) # Использует менеджер геометрии grid для размещения ярлыков и # текстовых полей в строку, чей индекс равен idx. label.grid(row=idx, column=0, sticky=«e») entry.grid(row=idx, column=1) # Создает новую рамку `frm_buttons` для размещения в ней # кнопок «Отправить» и «Очистить». Данная рамка заполняет # все окно в горизонтальном направлении с # отступами в 5 пикселей горизонтально и вертикально. frm_buttons = tk.Frame() frm_buttons.pack(fill=tk.X, ipadx=5, ipady=5) # Создает кнопку «Отправить» и размещает ее # справа от рамки `frm_buttons`. btn_submit = tk.Button(master=frm_buttons, text=«Submit») btn_submit.pack(side=tk.RIGHT, padx=10, ipadx=10) # Создает кнопку «Очистить» и размещает ее # справа от рамки `frm_buttons`. btn_clear = tk.Button(master=frm_buttons, text=«Clear») btn_clear.pack(side=tk.RIGHT, ipadx=10) # Запуск приложения. window.mainloop() |
В данном варианте список используется для хранения текста для каждого ярлыка формы. Они хранятся в том порядке, в котором поля формы должно появляться. После этого функция enumerate() возвращает индекс и строку каждого значения из списка labels
.
Разобравшись с заданием, можете переходить к следующей части урока.
Создание интерактивного приложения в Tkinter
Теперь у вас есть довольно хорошее представление о том, как создать окно с Tkinter, мы уже можем добавлять некоторые виджеты и управлять макетом приложения. Это здорово, но приложения должны не просто хорошо выглядеть — им нужно что-то делать! В этом разделе вы узнаете, как создать интерактивное приложение, которая будет выполнять какие-то действия при возникновении определенных событий.
Обработчика событий в Tkinter
При создании приложения в Tkinter, для старта цикла событий требуется вызвать метод window.mainloop()
. Во время цикла событий приложение проверяет, произошло ли какое либо событие. Если это так, то в ответ может быть выполнен какой-то метод или функция.
Цикл обработки событий предоставляется в Tkinter, поэтому не нужно писать дополнительный код для проверки наличия выполнения данных событий. Однако вам все же нужно написать код, который будет выполняться в ответ на событие. В Tkinter создаются функции, называемые обработчиками событий, для событий, которые используются в приложении.
На заметку: Событие — это любое действие, которое происходит во время цикла событий. Оно может вызвать некоторое поведение в приложении. Например, при нажатии клавиши с клавиатуры или кнопки мышки.
Когда происходит событие, создается объект события. Это значит, что создается экземпляр класса, представляющего событие. Вам не нужно беспокоиться о создании этих классов самостоятельно. Tkinter автоматически создаст для вас экземпляры классов событий.
Напишем собственный цикл обработки событий, чтобы лучше понять, как работает цикл обработки событий в Tkinter. Таким образом, вы сможете увидеть, как цикл событий в Tkinter вписывается в приложение, и какие части нужно написать самостоятельно.
Предположим, что есть список с названием events_list
, который содержит объекты событий. Новый объект события автоматически добавляется в список events_list
каждый раз, когда в программе происходит событие. Вам не нужно реализовывать механизм обновления. Это просто происходит автоматически в этом концептуальном примере. Используя бесконечный цикл, вы можете постоянно проверять, есть ли какие-либо объекты событий в events_list
:
# Предположим, что список автоматически обновляется events_list = [] # Запускаем цикл событий while True: # Если events_list пуст, тогда никаких событий не происходит # и можно пропустить следующую итерацию цикла. if events_list == []: continue # Если выполнение доходит до данной точки, значит, # есть по крайней мере одно событие в events_list. event = events_list[0] |
Прямо сейчас созданный цикл событий с самим событием event
ничего не делает. Давайте изменим это. Предположим, приложение должно реагировать на нажатия клавиш. Вам нужно проверить, что событие event
было создано пользователем при нажатии клавиши на клавиатуре, и, если это так, передать event
в функцию обработчика событий для нажатия клавиш.
Предположим, что event
имеет атрибут .type
, установленный на строку "keypress"
, если событие является объектом события нажатия клавиши, а также атрибут .char
, содержащий символ нажатой клавиши. Создадим новую функцию handle_keypress()
и обновим код цикла событий:
events_list = [] # Создает обработчик событий def handle_keypress(event): «»»Выводит символ, связанный с нажатой клавишей»»» print(event.char) while True: if events_list == []: continue event = events_list[0] # Если событие event является объектом нажатия клавиши keypress if event.type == «keypress»: # Вызывает обработчик события нажатия клавиши handle_keypress(event) |
При вызове метода window.mainloop()
запускается похожий цикл. Данный метод отвечает за две части цикла:
- Он поддерживает список событий, которые произошли в приложении;
- Он запускает обработчик событий каждый раз, когда новое событие добавляется в список.
Обновим цикл событий, чтобы использовать window.mainloop()
вместо вашего собственного цикла событий:
import tkinter as tk # Создает объект окна. window = tk.Tk() # Создает обработчик событий. def handle_keypress(event): «»»Выводит символ, связанный с нажатой клавишей»»» print(event.char) # Запускает обработчик событий. window.mainloop() |
Метод .mainloop()
отвечает за многое, но в вышеуказанном коде все-таки кое-что отсутствует. Как Tkinter узнает, когда использовать handle_keypress()
? У виджетов в Tkinter есть метод под названием .bind()
, предназначенный только для этой цели.
Метод .bind() для виджетов в Tkinter
Для вызова обработчика событий во время возникновения события, связанного с виджетом, используется метод .bind()
. Обработчик событий напрямую связан с событием. Продолжим использовать предыдущий пример с нажатием клавиши и задействуем метод .bind()
, чтобы связать handle_keypress()
с событием нажатия клавиши:
import tkinter as tk window = tk.Tk() def handle_keypress(event): «»»Выводит символ, связанный с нажатой клавишей»»» print(event.char) # Связывает событие нажатия клавиши с handle_keypress() window.bind(«<Key>», handle_keypress) window.mainloop() |
Здесь обработчик событий handle_keypress()
связывается с событием "<Key>"
, используя window.bind()
. Если во время работы приложения нажата определенная клавиша, тогда программа выведет символ этой нажатой клавиши.
На заметку: Результат вышеуказанной программы не выводится в окне приложения Tkinter. Он выводится в
stdout
(терминал).Если вы запускаете программу в IDLE, вывод будет в интерактивном окне. При запуске программы из терминала результат выведется в терминале.
Метод .bind()
всегда принимает по крайней мере два аргумента:
- Событие, представленное строкой в форме
"<event_name>"
, гдеevent_name
может быть любым событием; - Обработчик событий, что является названием функции, вызываемой во время срабатывания события.
Обработчик события связан с виджетом, для которого вызывается метод .bind()
. Когда вызывается обработчик события, объект события передается в функцию обработчика события.
В приведенном выше примере обработчик событий привязан к самому окну, но вы можете привязать обработчик событий к любому виджету в приложении. Например, вы можете привязать обработчик событий к виджету кнопки Button
, который будет выполнять некоторые действия при каждом нажатии на данную кнопку:
def handle_click(event): print(«Нажата кнопка!») button = tk.Button(text=«Кликни!») button.bind(«<Button-1>», handle_click) |
В данном примере событие "<Button-1>"
над виджетом кнопки связано с обработчиком handle_click
. Событие "<Button-1>"
, происходит когда при направлении курсора на виджет нажимается левая кнопка мыши.
Есть и другие события для кнопок мыши, включая "<Button-2>"
для средней кнопки мыши (в современных мышках это нажатая колесо для скролла) и "<Button-3>"
и правой кнопки мыши.
При помощи метода .bind()
с виджетом можно связать любой обработчик событий. Однако есть более простой способ связать обработчики событий с нажатием кнопки при помощи использования атрибута command
от виджета кнопки.
Атрибут command для виджета кнопки в Tkinter
У каждого виджета кнопки есть атрибут command
, который привязывает какую либо функцию к данной кнопки. Во время нажатия кнопки функция выполняется.
Взглянем на следующий пример. Сначала создается окно с ярлыком который содержит числовое значение. Справа и слева от ярлыка помещаются кнопки. Левая кнопка будет использоваться для уменьшения значения из ярлыка, а вторая кнопка для увеличения значения. Ниже представлен код для окна:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import tkinter as tk window = tk.Tk() window.rowconfigure(0, minsize=50, weight=1) window.columnconfigure([0, 1, 2], minsize=50, weight=1) btn_decrease = tk.Button(master=window, text=«-«) btn_decrease.grid(row=0, column=0, sticky=«nsew») lbl_value = tk.Label(master=window, text=«0») lbl_value.grid(row=0, column=1) btn_increase = tk.Button(master=window, text=«+») btn_increase.grid(row=0, column=2, sticky=«nsew») window.mainloop() |
Окно выглядит следующим образом:
Макет приложения определен, можно вдохнуть в него жизнь, назначив кнопкам определенные команды. Начнем с левой кнопки. При нажатии на нее значение должно увеличиваться на 1. Для этого нам нужно знать две вещи:
- Как получить текст из ярлыка?
- Как обновить текст в ярлыке?
У виджетов ярлыка нет метода .get()
в отличие от виджетов в возможностью ввода текста. Однако можно получить текста из ярлыка, через ключ text
как при работе с обычным словарем:
label = Tk.Label(text=«Hello») # Получение текста из ярлыка text = label[«text»] # Установка нового текста для ярлыка label[«text»] = «Good bye» |
Теперь, когда мы знаем, как получить и установить текст ярлыка, напишем функцию increase()
, которая увеличивает значение ярлыка lbl_value
на 1:
def increase(): value = int(lbl_value[«text»]) lbl_value[«text»] = f«{value + 1}» |
Функция increase()
получает текст из ярлыка lbl_value
и конвертирует его в целое число через int()
. Затем его значение увеличивает на 1, присваивая атрибуту text
из ярлыка это новое значение. В примере выше, мы использовали f-строки для форматирование строки.
Функция decrease()
нужна для уменьшения значения value_label
на 1:
def decrease(): value = int(lbl_value[«text»]) lbl_value[«text»] = f«{value — 1}» |
Функции increase()
и decrease()
помещаются в код сразу после оператора import.
Для связи кнопки с функцией нужно назначить атрибуту command
определенную функцию. Вы можете сделать это, когда создаете экземпляр этой кнопки. Например, чтобы назначить функцию increase()
для кнопки increase_button
, обновите код, в котором создается кнопка, следующим образом:
btn_increase = tk.Button( master=window, text=«+», command=increase ) |
Теперь присваиваем функцию decrease()
для кнопки decrease_button
:
btn_decrease = tk.Button( master=window, text=«-«, command=decrease ) |
Это все, что вам нужно сделать, чтобы связать кнопки с функциями increase()
и decrease()
и сделать программу работоспособной. Попробуйте сохранить изменения и запустить приложение. Нажмите на кнопки, чтобы увеличить или уменьшить значение в центре окна:
Ниже представлен код данного приложения:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
import tkinter as tk def increase(): value = int(lbl_value[«text»]) lbl_value[«text»] = f«{value + 1}» def decrease(): value = int(lbl_value[«text»]) lbl_value[«text»] = f«{value — 1}» window = tk.Tk() window.rowconfigure(0, minsize=50, weight=1) window.columnconfigure([0, 1, 2], minsize=50, weight=1) btn_decrease = tk.Button( master=window, text=«-«, command=decrease ) btn_decrease.grid(row=0, column=0, sticky=«nsew») lbl_value = tk.Label(master=window, text=«0») lbl_value.grid(row=0, column=1) btn_increase = tk.Button( master=window, text=«+», command=increase ) btn_increase.grid(row=0, column=2, sticky=«nsew») window.mainloop() |
Данное приложение сложно назвать полезным с практической точки зрения, но создавая его мы изучили полезные навыки для будущих проектов:
- Использование виджетов для создания компонентов пользовательского интерфейса;
- Использование менеджеров геометрии для управления макетом приложения;
- Создание функций для взаимодействия с различными компонентами для принятия и трансформирования пользовательского ввода.
В следующих двух разделах будет показано, как создать полезные приложения. Сначала сделаем конвертер температуры, которые переводит Фаренгейты в градусы Цельсия. После этого создадим текстовый редактор, который открывает, редактирует и сохраняет текстовые файлы.
Задание #4 — Бросаем игровые кости в Tkinter
Ниже дано еще одно задание для проверки понимания всего изученного.
Задание: Создать симулятор броска игральных костей.
Напишите программу, которая является симулятором результата броска шестигранной игральной кости. В приложении должна быть кнопка с текстом «Бросить». При нажатии на эту кнопку должно генерироваться и выводиться на экран случайное число от 1 до 6.
Подсказка: Случайное число можно сгенерировать с помощью randint() из модуля random.
В конечном итоге, приложение должно выглядеть следующим образом:
Попробуйте сделать все сами. В конце можете ознакомиться с еще одним вариантом кода который мы приготовили. Помните, что у каждого разработчика свой стиль, и ваша программа можете выглядеть по-другому.
Решение задачи #4 — Бросаем кости
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import random import tkinter as tk def roll(): lbl_result[«text»] = str(random.randint(1, 6)) window = tk.Tk() window.columnconfigure(0, minsize=150) window.rowconfigure([0, 1], minsize=50) btn_roll = tk.Button(text=«Бросить», command=roll) lbl_result = tk.Label() btn_roll.grid(row=0, column=0, sticky=«nsew») lbl_result.grid(row=1, column=0) window.mainloop() |
Когда разберетесь с заданием, переходите к следующей части.
Приложение по конвертированию температуры в Tkinter
В этом разделе вы создадите приложение для конвертирования температуры, которое позволит пользователю вводить температуру в градусах Фаренгейта и нажимать кнопку, чтобы преобразовать эту температуру в градусы Цельсия. Мы разберем код шаг за шагом. Полный код программы будет дан в конце раздела.
Перед написанием кода нужно задуматься о дизайне приложения. Нам потребуются следующие элементы:
- Виджет однострочного поля для ввода текста под названием
ent_temperature
для ввода значения температуры по Фаренгейту; - Виджет ярлыка под названием
lbl_result
для отображения итогового значения температуры по Цельсию; - Виджет кнопки под названием
btn_convert
, что читает значение текстового поля и конвертирует его из Фаренгейта в Цельсий, и после нажатия помещает результат в виде текста в ярлыке.
Вы можете расположить элементы в виде сетки с одной строкой и одним столбцом для каждого виджета. Получим небольшое, но очень удобное для пользователя приложение. У всех элементов должны быть ярлыки.
Ярлык помещается справа от текстового поля ent_temperature
с символом Фаренгейта (℉), чтобы пользователь знал, что значением в текстовом поле ent_temperature
нужно ввести в градусы Фаренгейта. Устанавливаем для ярлыка данный текст "N{DEGREE FAHRENHEIT}"
, это именованный Unicode символ в Python для отображения символа Фаренгейта.
Можно вставить кнопку btn_convert
немного изящества, установив для нее значение "N{RIGHTWARDS BLACK ARROW}"
, которое отображает черную стрелку, указывающую вправо. Также нужно, чтобы у ярлыка с результатом lbl_result
был символ Цельсия (℃), ярлык будет иметь следующее значение "N{DEGREE CELSIUS}"
для указания того, что результат в градусах Цельсия. Вот как будет выглядеть итоговое окно:
Теперь, когда перечень виджетов и внешний вид финального результата известны, можно приступить к делу. Для начала импортирует tkinter
и создаем новое окно.
import tkinter as tk window = tk.Tk() window.title(«Конвертер температуры») |
Метод window.title()
устанавливает заголовок для существующего окна. При запуске приложения у окна будет заголовок «Конвертер температуры». Далее создаем виджет однострочного текстового поля ent_temperature
с ярлыком lbl_temp
, вставляем их в рамку под названием frm_entry
:
frm_entry = tk.Frame(master=window) ent_temperature = tk.Entry(master=frm_entry, width=10) lbl_temp = tk.Label(master=frm_entry, text=«N{DEGREE FAHRENHEIT}») |
Однострочное текстовое поле ent_temperature
является местом, куда пользователь вводит значение по Фаренгейту. Перемнная lbl_temp
содержит ярлык для текстового поля ent_temperature
с символом Фаренгейта. Рамка frm_entry
является контейнером, что группирует текстовое поле ent_temperature
и ярлык lbl_temp
вместе.
Нам нужно, чтобы ярлык lbl_temp
находился справа от тектсового поля ent_temperature
. Их можно поместить в рамку frm_entry
, используя менеджер геометрии .grid()
с одной строкой и двумя столбцами:
ent_temperature.grid(row=0, column=0, sticky=«e») lbl_temp.grid(row=0, column=1, sticky=«w») |
Мы установили параметр sticky
на "e"
для текстового поля ent_temperature
таким образом, чтобы она всегда будет с правой стороны ячейки сетки. Также установили sticky
на "w"
для ярлыка lbl_temp
для закрепления с левой стороны его ячейки сетки.
Теперь ярлык lbl_temp
будет находиться сразу справа от текстового поля ent_temperature
.
Теперь заставим кнопку btn_convert
и ярлык с результатом lbl_result
конвертировать введенную в текстовом поле ent_temperature
температуру, после чего отобразить результат на экране:
btn_convert = tk.Button( master=window, text=«N{RIGHTWARDS BLACK ARROW}» ) lbl_result = tk.Label(master=window, text=«N{DEGREE CELSIUS}») |
Как и в случае с рамкой frm_entry
, виджеты кнопки btn_convert
и ярлык с результатом lbl_result
назначаются окну.
Вместе эти три виджета являются ячейками сетки приложения. Используем метод .grid()
, чтобы разместить их должным образом:
frm_entry.grid(row=0, column=0, padx=10) btn_convert.grid(row=0, column=1, pady=10) lbl_result.grid(row=0, column=2, padx=10) |
Теперь запускаем приложение:
Выглядит неплохо. Однако кнопки пока ничего не делают. В верхней части скрипта, прямо под строкой import
, добавим функцию под названием fahrenheit_to_celsius()
:
def fahrenheit_to_celsius(): «»» Конвертирует значение Фаренгейта в Цельсий и вставляет результат в ярлык lbl_result. «»» fahrenheit = ent_temperature.get() celsius = (5/9) * (float(fahrenheit) — 32) lbl_result[«text»] = f«{round(celsius, 2)} N{DEGREE CELSIUS}» |
Данная функция читает значение из текстового поля ent_temperature
, конвертирует его из Фаренгейтов в Цельсий, после чего отображает результат в ярлыке lbl_result
.
Вернемся к строке создания кнопки btn_convert
и назначим параметр command
на функцию fahrenheit_to_celsius
:
btn_convert = tk.Button( master=window, text=«N{RIGHTWARDS BLACK ARROW}», command=fahrenheit_to_celsius # <— Добавим его тут ) |
Вот и все! Мы создали полностью функционирующий конвертер температуры длиной всего в 26 строк кода. Неплохо, правда?
Ниже дан полный код программы конвертера температуры:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
import tkinter as tk def fahrenheit_to_celsius(): «»» Конвертирует значение из градусов по Фаренгейту в градусы по Цельсию и выводит результат в ярлык lbl_result. «»» fahrenheit = ent_temperature.get() celsius = (5/9) * (float(fahrenheit) — 32) lbl_result[«text»] = f«{round(celsius, 2)} N{DEGREE CELSIUS}» # Создание окна. window = tk.Tk() window.title(«Конвертер температуры») window.resizable(width=False, height=False) # Создание рамки для ввода значения по Фаренгейту через виджет # однострочного текстового поля вместе с ярлыком. frm_entry = tk.Frame(master=window) ent_temperature = tk.Entry(master=frm_entry, width=10) lbl_temp = tk.Label(master=frm_entry, text=«N{DEGREE FAHRENHEIT}») # Макет для рамки ввода температуры и ярлыка с символом Фаренгейта # использует менеджер геометрии .grid(). ent_temperature.grid(row=0, column=0, sticky=«e») lbl_temp.grid(row=0, column=1, sticky=«w») # Создание кнопки-конвертера и ярлыка для вывода результата. btn_convert = tk.Button( master=window, text=«N{RIGHTWARDS BLACK ARROW}», command=fahrenheit_to_celsius ) lbl_result = tk.Label(master=window, text=«N{DEGREE CELSIUS}») # Настройка макета через менеджер геометрии .grid(). frm_entry.grid(row=0, column=0, padx=10) btn_convert.grid(row=0, column=1, pady=10) lbl_result.grid(row=0, column=2, padx=10) # Запуск приложения. window.mainloop() |
В следующем разделе рассмотрим процесс создания текстового редактора для файлов.
Создание текстового редактора на Tkinter
В данном разделе будет рассмотрен процесс создания текстового редактора, который может открывать, редактировать и сохранять текстовые файлы. В приложении обязательно должны быть следующие элементы:
- Виджет кнопки под названием
btn_open
для открытия файла, которого нужно отредактировать; - Виджет кнопки под названием
btn_save
для сохранения изменений; - Виджет для ввода большого текста под названием
txt_edit
для создания и редактирования текстового файла.
Три виджета будут расположены таким образом, чтобы две кнопки находились с левой стороны окна, а текстовое поле — с правой стороны.
Все окно должно быть высотой минимум в 800 пикселей, и ширина текстового поля txt_edit
также должна быть минимум 800 пикселей. Весь макет должен быть адаптивным, так что если размер окна изменяется, то также изменяется размер текстового поля txt_edit
. Однако ширина рамки с кнопками не должна меняться.
Вот примерный набросок того, как будет выглядеть окно:
Добиться желаемого макета можно через менеджер геометрии .grid()
. В макете одна строка и два столбца:
- Узкий столбец слева от кнопок;
- Широкий столбец справа от текстового поля.
Чтобы установить минимальные размеры для окна и текстового поля txt_edit
, вы можете установить параметры minsize
используя методы окна .rowconfigure()
и .columnconfigure()
указав значение в 800 пикселей. Для обработки изменения размера окна, можно установить параметр weight
для выше перечисленных методов на 1.
Для размещения обеих кнопок в один и тот же столбец нужно создать виджет рамки под названием fr_buttons
. В соответствии с макетом, две кнопки должны быть расположены вертикально внутри рамки, с кнопкой btn_open
сверху. Это можно сделать с помощью менеджера геометрии .grid()
или .pack()
. Будем использовать .grid()
, так как с ним немного легче работать.
Теперь, когда у нас есть план, можно приступить к написанию приложения. Первый шаг — создать все нужные виджеты:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import tkinter as tk window = tk.Tk() window.title(«Простой текстовый редактор») window.rowconfigure(0, minsize=800, weight=1) window.columnconfigure(1, minsize=800, weight=1) txt_edit = tk.Text(window) fr_buttons = tk.Frame(window) btn_open = tk.Button(fr_buttons, text=«Открыть») btn_save = tk.Button(fr_buttons, text=«Сохранить как…») btn_open.grid(row=0, column=0, sticky=«ew», padx=5, pady=5) btn_save.grid(row=1, column=0, sticky=«ew», padx=5) fr_buttons.grid(row=0, column=0, sticky=«ns») txt_edit.grid(row=0, column=1, sticky=«nsew») window.mainloop() |
Разберем код поэтапно:
- Строка 1 импортирует библиотеку
tkinter
; - Строки 3 и 4 создают новое окно с заголовком «Простой текстовый редактор»;
- Строки 6 и 7 устанавливают конфигурацию строк и столбцов;
- Строки 9 и 12 создают четыре виджета — текстовый бокс, рамку, кнопка для открытия и кнопка для сохранения файла.
Подробнее рассмотрим строку 6. Параметр minsize
для метода .rowconfigure()
ставится на 800 пикселей, weight
имеет значение 1
:
window.rowconfigure(0, minsize=800, weight=1) |
Первый аргумент — 0, устанавливает высоту первой строки на 800 пикселей, гарантируя, что высота строки увеличивается пропорционально высоте окна. В макете приложения только одна строка, поэтому эти параметры применяются ко всему окну.
Давайте также подробнее рассмотрим строку 7. Здесь используется метод .columnconfigure()
, чтобы установить атрибуты width
и weight
столбца с индексами от 1 до 800 и 1 соответственно:
window.columnconfigure(1, minsize=800, weight=1) |
Помните, что индексы строк и столбцов начинаются с нуля, поэтому эти параметры применяются только ко второму столбцу. При настройке только второго столбца текстовое поле будет расширяться и сокращаться естественным образом при изменении размера окна, в то время как столбец, содержащий кнопки, будет оставаться на фиксированной ширине.
Теперь можно работать над макетом приложения. Сначала назначим две кнопки в рамку fr_buttons
с помощью менеджера геометрии .grid()
:
btn_open.grid(row=0, column=0, sticky=«ew», padx=5, pady=5) btn_save.grid(row=1, column=0, sticky=«ew», padx=5) |
Эти две строки кода создают сетку с двумя строками и одним столбцом в рамке fr_buttons
, поскольку для кнопки btn_open
и кнопки btn_save
атрибут master
указывает на рамку fr_buttons
. Кнопка btn_open
помещается в первый ряд, а кнопка btn_save
— во второй ряд, так что кнопка btn_open
отображается над кнопкой btn_save
в макете, как и было запланировано в изначальном макете.
Для кнопок btn_open
и btn_save
атрибуты sticky
установлены на "ew"
, что заставляет кнопки расширяться горизонтально в обоих направлениях и заполнять всю рамку. Это гарантирует, что обе кнопки имеют одинаковый размер.
Указывается 5 пикселей отступа вокруг каждой кнопки, устанавливая параметры padx
и pady
на 5. Только у кнопки btn_open
есть вертикальный отступ. Поскольку он находится сверху, вертикальный отступ немного смещает кнопку вниз от верхней части окна и обеспечивает небольшой зазор между ним и кнопкой btn_save
.
Теперь, когда рамка fr_buttons
разложена и готова к работе, вы можете настроить макет сетки для остальной части окна:
fr_buttons.grid(row=0, column=0, sticky=«ns») txt_edit.grid(row=0, column=1, sticky=«nsew») |
Эти две строки кода создают сетку с одной строкой и двумя столбцами для окна. Вы помещаете рамку fr_buttons
в первый столбец и текстовое поле txt_edit
во второй столбец, так что рамка с кнопками fr_buttons
появляется слева от тектсового поля txt_edit
в макете окна приложения.
Параметр sticky
для рамки с кнопками fr_buttons
имеет значение "ns"
, что заставляет всю рамку расширяться по вертикали и заполнять всю высоту его столбца. Текстовое поле txt_edit
заполняет всю ячейку сетки, потому что вы установили для ее параметра sticky
значение "nsew"
, что заставляет его расширяться во всех направлениях.
Теперь, когда макет приложения готов, добавьте метод window.mainloop()
в конец программы, сохраните и запустите скрипт. Появится следующее окно:
Выглядит неплохо! Но приложение пока ничего не делает, поэтому нужно создать команды для кнопок. Кнопка btn_open
должена показать диалоговое окно выбора файла и позволить пользователю выбрать файл с компьютера. Затем он должен открыть файл и вставить его содержимое в текстом поле txt_edit
. Для этого используем функцию open_file()
:
def open_file(): «»»Открывает файл для редактирования»»» filepath = askopenfilename( filetypes=[(«Text Files», «*.txt»), («All Files», «*.*»)] ) if not filepath: return txt_edit.delete(«1.0», tk.END) with open(filepath, «r») as input_file: text = input_file.read() txt_edit.insert(tk.END, text) window.title(f«Simple Text Editor — {filepath}») |
Разберем данную функцию поэтапно:
- Строки с 3 по 5 используют диалоговое окно
askopenfilename
из модуляtkinter.filedialog
, чтобы отобразить диалоговое окно открытия файла и сохранить выбранный путь к файлу в переменнуюfilepath
; - Строки 6 и 7 проверяют, закрывает ли пользователь диалоговое окно или нажимает кнопку отмены. Если это так, то
filepath
будет иметь значениеNone
, и функция вернется без выполнения какого-либо кода для чтения содержимого файла и вставки текста в текстовом полеtxt_edit
; - Строка 8 очищает текущее содержимое из текстового поля
txt_edit
, используя метод.delete()
; - Строки 9 и 10 открывают выбранный файл и читают через
.read()
его содержимое перед сохранением текста в виде строки; - Строка 11 вставляем текст в текстовом поле
txt_edit
, используя метод.insert()
; - Строка 12 устанавливает заголовок окна так, чтобы он содержал путь к открытому файлу.
Теперь вы можете обновить программу так, чтобы кнопка btn_open
вызывала функцию open_file()
при каждом нажатии. Есть несколько вещей, которые нужно сделать, чтобы обновить программу.
Сначала импортируйте askopenfilename
из модуля tkinter.filedialog
, добавив следующий импорт в начало вашей программы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import tkinter as tk from tkinter.filedialog import askopenfilename window = tk.Tk() window.title(«Простой текстовый редактор») window.rowconfigure(0, minsize=800, weight=1) window.columnconfigure(1, minsize=800, weight=1) txt_edit = tk.Text(window) fr_buttons = tk.Frame(window) btn_open = tk.Button(fr_buttons, text=«Открыть») btn_save = tk.Button(fr_buttons, text=«Сохранить как…») btn_open.grid(row=0, column=0, sticky=«ew», padx=5, pady=5) btn_save.grid(row=1, column=0, sticky=«ew», padx=5) fr_buttons.grid(row=0, column=0, sticky=«ns») txt_edit.grid(row=0, column=1, sticky=«nsew») window.mainloop() |
Затем добавляется тело функции open_file()
прямо под оператором импорта:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
import tkinter as tk from tkinter.filedialog import askopenfilename def open_file(): «»»Открываем файл для редактирования»»» filepath = askopenfilename( filetypes=[(«Текстовые файлы», «*.txt»), («Все файлы», «*.*»)] ) if not filepath: return txt_edit.delete(«1.0», tk.END) with open(filepath, «r») as input_file: text = input_file.read() txt_edit.insert(tk.END, text) window.title(f«Простой текстовый редактор — {filepath}») window = tk.Tk() window.title(«Простой текстовый редактор») window.rowconfigure(0, minsize=800, weight=1) window.columnconfigure(1, minsize=800, weight=1) txt_edit = tk.Text(window) fr_buttons = tk.Frame(window) btn_open = tk.Button(fr_buttons, text=«Открыть») btn_save = tk.Button(fr_buttons, text=«Сохранить как…») btn_open.grid(row=0, column=0, sticky=«ew», padx=5, pady=5) btn_save.grid(row=1, column=0, sticky=«ew», padx=5) fr_buttons.grid(row=0, column=0, sticky=«ns») txt_edit.grid(row=0, column=1, sticky=«nsew») window.mainloop() |
Теперь указываем атрибуту command
от кнопки btn_open
на функцию open_file
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
import tkinter as tk from tkinter.filedialog import askopenfilename def open_file(): «»»Открываем файл для редактирования»»» filepath = askopenfilename( filetypes=[(«Текстовые файлы», «*.txt»), («Все файлы», «*.*»)] ) if not filepath: return txt_edit.delete(«1.0», tk.END) with open(filepath, «r») as input_file: text = input_file.read() txt_edit.insert(tk.END, text) window.title(f«Простой текстовый редактор — {filepath}») window = tk.Tk() window.title(«Простой текстовый редактор») window.rowconfigure(0, minsize=800, weight=1) window.columnconfigure(1, minsize=800, weight=1) txt_edit = tk.Text(window) fr_buttons = tk.Frame(window) btn_open = tk.Button(fr_buttons, text=«Открыть», command=open_file) btn_save = tk.Button(fr_buttons, text=«Сохранить как…») btn_open.grid(row=0, column=0, sticky=«ew», padx=5, pady=5) btn_save.grid(row=1, column=0, sticky=«ew», padx=5) fr_buttons.grid(row=0, column=0, sticky=«ns») txt_edit.grid(row=0, column=1, sticky=«nsew») window.mainloop() |
Сохраните файл и запустите его, чтобы убедиться, что все работает. Затем попробуйте открыть текстовый файл.
Теперь, наша кнопка btn_open
работает и успешно открывает текстовые файлы, можно уже заняться функцией для кнопки btn_save
. Для этого необходимо открыть диалоговое окно сохранения файла, чтобы пользователь мог выбрать, куда он хотел бы сохранить файл.
Для этого вы будете использовать диалог asksaveasfilename
из модуля tkinter.filedialog
. Эта функция также должна извлечь все содержимое из текстового поля txt_edit
и записать его в файл в выбранном месте. Вот функция, которая делает именно это:
def save_file(): «»»Сохраняем текущий файл как новый файл.»»» filepath = asksaveasfilename( defaultextension=«txt», filetypes=[(«Текстовые файлы», «*.txt»), («Все файлы», «*.*»)], ) if not filepath: return with open(filepath, «w») as output_file: text = txt_edit.get(«1.0», tk.END) output_file.write(text) window.title(f«Простой текстовый редактор — {filepath}») |
Разберем код:
- Строки с 3 по 6 используют диалоговое окно
asksaveasfilename
, чтобы выбрать желаемое место сохранения файла. Выбранный путь к файлу сохраняется в переменнуюfilepath
; - Строки 7 и 8 проверяют, закрывает ли пользователь диалоговое окно или нажимает кнопку отмены. Если это так, то переменная
filepath
будет иметь значениеNone
, и функция завершиться без выполнения какого-либо кода для сохранения текста в файле; - Строка 9 создает новый файл по выбранному пути;
- Строка 10 извлекает текст из текстового поля
txt_edit
с помощью метода.get()
и присваивает его переменнойtext
; - Строка 11 записывает содержимое из переменной
text
в выбранном файле; - Строка 12 обновляет заголовок окна приложения, чтобы новый путь к файлу отображался в заголовке окна.
Теперь вы можете обновить программу, чтобы кнопка btn_save
вызывала функцию save_file()
при нажатии. Опять же, есть несколько вещей, которые вам нужно сделать, чтобы обновить программу.
Сначала импортируйте asksaveasfilename
из модуля tkinter.filedialog
, обновив импорт в верхней части вашего скрипта, например так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import tkinter as tk from tkinter.filedialog import askopenfilename, asksaveasfilename def open_file(): «»»Открываем файл для редактирования»»» filepath = askopenfilename( filetypes=[(«Текстовые файлы», «*.txt»), («Все файлы», «*.*»)] ) if not filepath: return txt_edit.delete(«1.0», tk.END) with open(filepath, «r») as input_file: text = input_file.read() txt_edit.insert(tk.END, text) window.title(f«Простой текстовый редактор — {filepath}») window = tk.Tk() window.title(«Простой текстовый редактор») window.rowconfigure(0, minsize=800, weight=1) window.columnconfigure(1, minsize=800, weight=1) txt_edit = tk.Text(window) fr_buttons = tk.Frame(window, relief=tk.RAISED, bd=2) btn_open = tk.Button(fr_buttons, text=«Открыть», command=open_file) btn_save = tk.Button(fr_buttons, text=«Сохранить как…») btn_open.grid(row=0, column=0, sticky=«ew», padx=5, pady=5) btn_save.grid(row=1, column=0, sticky=«ew», padx=5) fr_buttons.grid(row=0, column=0, sticky=«ns») txt_edit.grid(row=0, column=1, sticky=«nsew») window.mainloop() |
Затем добавляем функцию save_file()
прямо под функцию open_file()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
import tkinter as tk from tkinter.filedialog import askopenfilename, asksaveasfilename def open_file(): «»»Открываем файл для редактирования»»» filepath = askopenfilename( filetypes=[(«Текстовые файлы», «*.txt»), («Все файлы», «*.*»)] ) if not filepath: return txt_edit.delete(«1.0», tk.END) with open(filepath, «r») as input_file: text = input_file.read() txt_edit.insert(tk.END, text) window.title(f«Простой текстовый редактор — {filepath}») def save_file(): «»»Сохраняем текущий файл как новый файл.»»» filepath = asksaveasfilename( defaultextension=«txt», filetypes=[(«Текстовые файлы», «*.txt»), («Все файлы», «*.*»)], ) if not filepath: return with open(filepath, «w») as output_file: text = txt_edit.get(«1.0», tk.END) output_file.write(text) window.title(f«Простой текстовый редактор — {filepath}») window = tk.Tk() window.title(«Простой текстовый редактор») window.rowconfigure(0, minsize=800, weight=1) window.columnconfigure(1, minsize=800, weight=1) txt_edit = tk.Text(window) fr_buttons = tk.Frame(window, relief=tk.RAISED, bd=2) btn_open = tk.Button(fr_buttons, text=«Открыть», command=open_file) btn_save = tk.Button(fr_buttons, text=«Сохранить как…») btn_open.grid(row=0, column=0, sticky=«ew», padx=5, pady=5) btn_save.grid(row=1, column=0, sticky=«ew», padx=5) fr_buttons.grid(row=0, column=0, sticky=«ns») txt_edit.grid(row=0, column=1, sticky=«nsew») window.mainloop() |
Наконец, указываем атрибуту command
от кнопки btn_save
на функцию save_file
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
import tkinter as tk from tkinter.filedialog import askopenfilename, asksaveasfilename def open_file(): «»»Открываем файл для редактирования»»» filepath = askopenfilename( filetypes=[(«Текстовые файлы», «*.txt»), («Все файлы», «*.*»)] ) if not filepath: return txt_edit.delete(«1.0», tk.END) with open(filepath, «r») as input_file: text = input_file.read() txt_edit.insert(tk.END, text) window.title(f«Простой текстовый редактор — {filepath}») def save_file(): «»»Сохраняем текущий файл как новый файл.»»» filepath = asksaveasfilename( defaultextension=«txt», filetypes=[(«Текстовые файлы», «*.txt»), («Все файлы», «*.*»)], ) if not filepath: return with open(filepath, «w») as output_file: text = txt_edit.get(«1.0», tk.END) output_file.write(text) window.title(f«Простой текстовый редактор — {filepath}») window = tk.Tk() window.title(«Простой текстовый редактор») window.rowconfigure(0, minsize=800, weight=1) window.columnconfigure(1, minsize=800, weight=1) txt_edit = tk.Text(window) fr_buttons = tk.Frame(window, relief=tk.RAISED, bd=2) btn_open = tk.Button(fr_buttons, text=«Открыть», command=open_file) btn_save = tk.Button(fr_buttons, text=«Сохранить как…», command=save_file) btn_open.grid(row=0, column=0, sticky=«ew», padx=5, pady=5) btn_save.grid(row=1, column=0, sticky=«ew», padx=5) fr_buttons.grid(row=0, column=0, sticky=«ns») txt_edit.grid(row=0, column=1, sticky=«nsew») window.mainloop() |
Сохраните файл и запустите его. Теперь у вас есть небольшой, но полностью функциональный текстовый редактор написанный на Python используя библиотеку Tkinter.
Теперь вы создали два приложения с графическим интерфейсом на Python, использовав многие аспекты из текущего руководства. Это немалое достижение, можете собой гордиться. Теперь вы готовы для создания собственных приложений с графическим интерфейсом.
Заключение
Из этого урока вы узнали, как начать работу с программированием на Python используя графический интерфейс. Tkinter является хорошим выбором как GUI фреймворк, поскольку он встроен в стандартную библиотеку Python, и создание приложений с ним относительно несложно.
В этом руководстве вы узнали несколько важных концепций от Tkinter:
- Как работать с виджетами;
- Как управлять макетом приложения с помощью менеджеров геометрии;
- Как сделать ваши приложения интерактивными;
- Как использовать пять основных виджетов из Tkinter (
Label
,Button
,Entry
,Text
иFrame
).
Теперь, когда вы освоили основы программирования на Python используя графический интерфейс при помощью Tkinter, следующим шагом будет создание ваших собственных приложений. Что это будет? Поделитесь идеями для своих проектов в комментариях ниже.
Дополнительные материалы для изучения Tkinter
В этом уроке вы затронули только основы создания приложений с графическим интерфейсом в Python используя Tkinter. Есть ряд дополнительных тем, которые здесь не рассматривались. В этом разделе вы найдете некоторые из лучших доступных ресурсов, которые помогут продолжить путешествие в мир Tkinter.
Вот некоторые официальные ресурсы, которые можно просмотреть:
- Официальное руководство Python Tkinter, в котором подробно описан данный модуль. Текст предназначен для более продвинутых пользователей, новичкам будет сложновато;
- Справочник по Tkinter 8.5: GUI для Python — это обширный справочник, охватывающий большинство модулей от Tkinter. Он исчерпывающий, но написан кратко и без комментариев и примеров.
- Справочник по Tk — это полное руководство по командам в библиотеке Tk. Он написан для языка Tcl, но отвечает на множество вопросов о том, почему все работает так, как они работают в Tkinter. В официальной документации по Python есть раздел, посвященный отображению базового Tk в Tkinter, который необходим при чтении документации по командам Tk.
Дополнительные виджеты
В этом руководстве вы узнали о виджетах Label
, Button
, Entry
, Text
и Frame
. В Tkinter есть несколько других виджетов, каждый из которых необходим для создания реальных приложений. Вот несколько ресурсов, чтобы продолжить изучение виджетов:
- TkDocs Tkinter Tutorial — это достаточно обширное руководство для Tk, базовой библиотеки кода, используемой Tkinter. Примеры представлены на ткаих языка программирования как Python, Ruby, Perl и Tcl. Вы можете найти несколько примеров виджетов, помимо описанных в данной статье;
- Базовые виджеты включают те же виджеты, что и в этом руководстве, а также некоторые другие;
- Раздел Больше виджетов охватывает несколько дополнительных виджетов.
В официальной документации Python есть три раздела, охватывающих дополнительные виджеты:
- Тематические виджеты ttk набор тематических виджетов Tk;
- Расширение виджетов для Tk охватывает виджеты в наборе расширений интерфейса Tk;
- Виджет прокрутки текста расширяет возможности виджета
Text
в сочетании с вертикальной полосой прокрутки.
Поделиться приложением на Tkinter
Создав приложение с помощью Tkinter, вы, вероятно, захотите распространить его среди своих коллег и друзей. Вот несколько уроков, которые помогут вам в этом процессе:
- Использование PyInstaller для компиляции приложений
- 4 попытки упаковки Python как исполняемого файла
- Создание автономных приложений Python с помощью PyOxidizer
Другие GUI фреймворки
Tkinter — не единственный выбор для создания GUI приложений на Python. Если Tkinter не соответствует потребностям вашего проекта, задумайтесь об использовании другого фреймворка:
- Полный курс уроков по wxPython
- Python и PyQt5: создание калькулятора на PyQt5
- Создание мобильного приложения с Kivy Python Framework
Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.
E-mail: vasile.buldumac@ati.utm.md
Образование
Universitatea Tehnică a Moldovei (utm.md)
- 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»
Последнее обновление: 26.09.2022
Руководство по созданию графических приложений с помощью Tkinter на языке программирования Python
-
Глава 1. Основы Tkinter
-
Введение в Tkinter. Первая программа
-
Окно приложения
-
-
Глава 2. Виджеты
-
Введение в виджеты. Tk и ttk
-
Кнопки
-
Позиционирование. Pack
-
Позиционирование. Place
-
Позиционирование. Grid
-
Обработка событий
-
Текстовая метка Label
-
Поле ввода Entry
-
Привязка виджетов к переменным
-
Checkbutton
-
Radiobutton
-
Установка родительского контейнера. Frame
-
Listbox
-
Scrollbar и прокрутка виджета
-
Combobox
-
Scale
-
Spinbox
-
Progressbar
-
>Меню
-
Notebook. Создание вкладок
-
-
Глава 3. Виджет Text
-
Создание многострочного текстового поля
-
Основные операции с виджетом Text
-
Стилизация и добавление виджетов в Text
-
-
Глава 4. Виджет Treeview. Создание таблиц и деревьев
-
Управление данными в Treeview
-
Создание таблиц
-
Нажатие на заголовок столбца и сортировка
-
Выделение строк таблицы
-
Создание дерева
-
-
Глава 5. Окна
-
Создание окон
-
MessageBox
-
Диалоговые окна
-
-
Глава 6. Стилизация
-
Шрифты
-
Установка цвета
-
Курсоры
-
Установка стилей
-
Темы
-
-
Глава 7. Canvas
-
Добавление элементов на Canvas
-
Управление элементами в Canvas
-
Установка тегов
-
Привязка событий
-
Введение
Этой библиотеке посвящено мало внимания, и найти в рунете курс, книгу или FAQ по ней довольно-таки сложно. Стоит отметить, что здесь отражены только основы этой библиотеки, и надеюсь, что более опытные люди дополнят эту статью.
Что такое Tkinter?
Tkinter (от англ. tk interface) — это графическая библиотека, позволяющая создавать программы с оконным интерфейсом. Эта библиотека является интерфейсом к популярному языку программирования и инструменту создания графических приложений tcl/tk. Tkinter, как и tcl/tk, является кроссплатформенной библиотекой и может быть использована в большинстве распространённых операционных систем (Windows, Linux, Mac OS X и др.).
Так как Tkinter является достаточно прозрачным интерфейсом к tcl/tk, то основным источником информации для неё являются man-страницы tcl/tk. Эти страницы имеются в любой Unix-системе (в разделе n или 3tk). Также они доступны онлайн на сайте http://tcl.tk. Основные:
- Список разделов
- Список виджетов и команд
- Список общих опций для виджетов
Начиная с версии python-3.0 библиотека переименована в соответствии с PEP 8 в tkinter (с маленькой буквы).
Импортируется она как и любая другая библиотека:
# для версии python 2.7 и ниже import Tkinter # для версии python 3.0 и выше import tkinter
или
# для версии python 2.7 и ниже from Tkinter import * # для версии python 3.0 и выше from tkinter import *
В Tkinter визуальные контроллы называются виджетами (widget, от англ. window gadget) — стандартизированный компонент графического интерфейса, с которым взаимодействует пользователь.
Класс Tk
Tk является базовым классом любого Tkinter приложения. При создании объекта этого класса запускается интерпретатор tcl/tk и создаётся базовое окно приложения.
Tkinter является событийно-ориентированной библиотекой. В приложениях такого типа имеется главный цикл обработки событий. В Tkinter такой цикл запускается методом mainloop. Для явного выхода из интерпретатора и завершения цикла обработки событий используется метод quit.
Таким образом минимальное приложение на Tkinter будет таким:
from tkinter import * root = Tk() root.mainloop()
В приложении можно использовать несколько интерпретаторов tcl/tk. Так как после вызова метода mainloop дальнейшие команды python исполняться не будут до выхода из цикла обработки событий, необходимо метод mainloop всех интерпретаторов кроме последнего осуществлять в фоновом режиме. Пример запуска двух интерпретаторов:
from tkinter import * root1 = Tk() root2 = Tk() root1.after(500, root1.mainloop) # первый цикл запускаем в фоне root2.mainloop()
При использовании двух и более интерпретаторов необходимо следить, чтобы объекты, созданные в одном интерпретаторе, использовались только в нём. Например, изображение, созданное в первом интерпретаторе, может быть использовано много раз в этом же интерпретаторе, но не может быть использовано в других интерпретаторах. Необходимость в запуске нескольких интерпретаторов в одном приложении возникает крайне редко. Для создания дополнительного окна приложения в большинстве случаев достаточно виджета Toplevel.
Общее для всех виджетов
Все виджеты в Tkinter обладают некоторыми общими свойствами. Опишем их, перед тем как перейти к рассмотрению конкретных виджетов. Виджеты создаются вызовом конструктора соответствующего класса. Первый аргумент (как правило неименованный, но можно использовать имя master) это родительский виджет, в который будет упакован (помещён) наш виджет. Родительский виджет можно не указывать, в таком случае будет использовано главное окно приложения. Далее следуют именованные аргументы, конфигурирующие виджет. Это может быть используемый шрифт (font=…), цвет виджета (bg=…), команда, выполняющаяся при активации виджета (command=…) и т.д. Полный список всех аргументов можно посмотреть в man options и man-странице соответствующего виджета (например man button, см. разделы «STANDARD OPTIONS» и «WIDGET-SPECIFIC OPTIONS»). Пример кода:
from Tkinter import * def button_clicked(): print (u"Клик!") root=Tk() # кнопка по умолчанию button1 = Button() button1.pack() # кнопка с указанием родительского виджета и несколькими аргументами button2 = Button(root, bg="red", text=u"Кликни меня!", command=button_clicked) button2.pack() root.mainloop()
Памятуя о Zen Python (явное лучше неявного) указываю: данный код написан и работает для Python v 2. В случае использования Python v 3 код немного изменится.
1. tkinter с маленькой буквы.
2. print в круглых скобках () и без u.
Методы виджетов
- configure, config
Виджеты могут быть сконфигурированы во время создания, но иногда необходимо изменить конфигурацию виджета во время исполнения программы. Для этого используется метод configure (или его синоним config). Также можно использовать квадратные скобки (widget[‘option’] = new_value). Пример, программа выводит текущее время, после клика по кнопке:
from Tkinter import * import time def button_clicked(): # изменяем текст кнопки button['text'] = time.strftime('%H:%M:%S') root=Tk() # создаём виджет button = Button(root) # конфигурируем виджет после создания button.configure(text=time.strftime('%H:%M:%S'), command=button_clicked) # также можно использовать квадратные скобки: # button['text'] = time.strftime('%H:%M:%S') # button['command'] = button_clicked button.pack() root.mainloop()
В этом коде функция button_clicked вызывается каждый раз, когда пользователь кликает по кнопке.
- cget
Метод cget является обратным к методу configure. Он предназначен для получения информации о конфигурации виджета. Здесь как и в случае с configure можно использовать квадратные скобки (value = widget[‘option’]). Пример, после клика на кнопку программа показывает цвет кнопки и меняет его на другой:
from Tkinter import * from random import random def button_clicked(): button['text'] = button['bg'] # показываем предыдущий цвет кнопки bg = '#%0x%0x%0x' % (int(random()*16), int(random()*16), int(random()*16)) button['bg'] = bg button['activebackground'] = bg root=Tk() button = Button(root, command=button_clicked) button.pack() root.mainloop()
- destroy
Уничтожение виджета и всех его потомков. Стоит отметить, что если необходимо только на время спрятать какой-либо виджет, то лучше пользоваться упаковщиком grid и методом grid_remove:
from Tkinter import * def hide_show(): if label.winfo_viewable(): label.grid_remove() else: label.grid() root=Tk() label = Label(text=u'Я здесь!') label.grid() button = Button(command=hide_show, text=u"Спрятать/показать") button.grid() root.mainloop()
Использование grid_remove позволяет сохранять взаимное расположение виджетов.
- grab_*[1]
Методы семейства grab_ предназначены для управления потоком события. Виджет, захвативший поток, будет получать все события окна или приложения.
- grab_set — передать поток данному виджету
- grab_set_global — передать глобальный поток данному виджету. В этом случае все события на дисплее будут передаваться этому виджету. Следует пользоваться очень осторожно, т.к. остальные виджеты всех приложений не будут получать события.
- grab_release — освободить поток
- grab_status — узнать текущий статус потока событий для виджета. Возможные значения: None, «local» или «global».
- grab_current — получить виджет, который получает поток
Пример, приложение захватывает глобальный поток и освобождает его через 10 секунд:
from Tkinter import * root=Tk() root.after(200, root.grab_set_global) root.after(10000, root.grab_release) root.mainloop()
- focus_*[2]
Методы семейства focus_ используются для управления фокусом ввода с клавиатуры. Виджет, имеющий фокус, получает все события с клавиатуры.
- focus (синоним focus_set) — передать фокус виджету.
- focus_force — передать фокус, даже если приложение не имеет фокуса. Используйте осторожно, поскольку это может раздражать пользователей.
- focus_get — возвращает виджет, на который направлен фокус, либо None, если такой отсутствует.
- focus_displayof — возвращает виджет, на который направлен фокус на том дисплее, на котором размещён виджет, либо None, если такой отсутствует.
- focus_lastfor — возвращает виджет, на который будет направлен фокус, когда окно с этим виджетом получит фокус.
- tk_focusNext — возвращает виджет, который получит фокус следующим (обычно смена фокуса происходит при нажатии клавиши Tab). Порядок следования определяется последовательностью упаковки виджетов.
- tk_focusPrev — то же, что и focusNext, но в обратном порядке.
- tk_focusFollowsMouse — устанавливает, что виджет будет получать фокус при наведении на него мышью. Вернуть нормальное поведение достаточно сложно.
«Системные» методы
Эти методы не являются виджет-специфичными, т.е. хотя они являются методами виджетов они влияют на работу интерпретатора tcl/tk.
after, after_idle и after_cancel[3]
Таймеры. С помощью этих методов вы можете отложить выполнение какого-нибудь кода на определённое время.
after — принимает два аргумента: время в миллисекундах и функцию, которую надо выполнить через указанное время. Возвращает идентификатор, который может быть использован в after_cancel.
after_idle — принимает один аргумент — функцию. Эта функция будет выполнена после завершения всех отложенных операций (после того, как будут обработаны все события). Возвращает идентификатор, который может быть использован в after_cancel.
after_cancel — принимает один аргумент: идентификатор задачи, полученный предыдущими функциями, и отменяет это задание.
Пример, часы:
from Tkinter import * import time def tick(): label.after(200, tick) label['text'] = time.strftime('%H:%M:%S') root=Tk() label = Label(font='sans 20') label.pack() label.after_idle(tick) root.mainloop()
update и update_idletasks[4]
Две функции, для работы с очередью задач. Их выполнение вызывает обработку отложенных задач.
update_idletasks выполняет задачи, обычно откладываемые «на потом», когда приложение будет простаивать. Это приводит к прорисовке всех виджетов, расчёту их расположения и т.д. Обычно эта функция используется если были внесены изменения в состояние приложения, и вы хотите, чтобы эти изменения были отображены на экране немедленно, не дожидаясь завершения сценария.
update обрабатывает все задачи, стоящие в очереди. Обычно эта функция используется во время «тяжёлых» расчётов, когда необходимо чтобы приложение оставалось отзывчивым на действия пользователя.
Пример:
from Tkinter import * import math def hard_job(): x = 1000 while True: x = math.log(x) ** 2.8 root.update() root=Tk() button = Button() button.pack() root.after(500, hard_job) root.mainloop()
eval и evalfile
Две недокументированные функции для выполнения кода на tcl. eval позволяет выполнить строку на языке программирования tcl, а evalfile — выполнить код, записанный в файл. В качестве аргументов принимают соответственно строку и путь к файлу. Данные функции полезны при использовании дополнительных модулей, написанных на tcl. Пример:
from Tkinter import * root=Tk() root.eval('package require tile; ttk::style theme use clam') root.eval('ttk::button .b -text {ttk button}; pack .b') root.mainloop()
Основные виджеты
Toplevel
Toplevel[5] — окно верхнего уровня. Обычно используется для создания многооконных программ, а также для диалоговых окон.
- Методы виджета
- title — заголовок окна
- overrideredirect — указание оконному менеджеру игнорировать это окно. Аргументом является True или False. В случае, если аргумент не указан — получаем текущее значение. Если аргумент равен True, то такое окно будет показано оконным менеджером без обрамления (без заголовка и бордюра). Может быть использовано, например, для создания splashscreen при старте программы.
- iconify / deiconify — свернуть / развернуть окно
- withdraw — «спрятать» (сделать невидимым) окно. Для того, чтобы снова показать его, надо использовать метод deiconify.
- minsize и maxsize — минимальный / максимальный размер окна. Методы принимают два аргумента — ширина и высота окна. Если аргументы не указаны — возвращают текущее значение.
- state — получить текущее значение состояния окна. Может возвращать следующие значения: normal (нормальное состояние), icon (показано в виде иконки), iconic (свёрнуто), withdrawn (не показано), zoomed (развёрнуто на полный экран, только для Windows и Mac OS X)
- resizable — может ли пользователь изменять размер окна. Принимает два аргумента — возможность изменения размера по горизонтали и по вертикали. Без аргументов возвращает текущее значение.
- geometry — устанавливает геометрию окна в формате ширинаxвысота+x+y (пример: geometry(«600×400+40+80») — поместить окно в точку с координатам 40,80 и установить размер в 600×400). Размер или координаты могут быть опущены (geometry(«600×400») — только изменить размер, geometry(«+40+80») — только переместить окно).
- transient — сделать окно зависимым от другого окна, указанного в аргументе. Будет сворачиваться вместе с указанным окном. Без аргументов возвращает текущее значение.
- protocol — получает два аргумента: название события и функцию, которая будет вызываться при наступлении указанного события. События могут называться WM_TAKE_FOCUS (получение фокуса), WM_SAVE_YOURSELF (необходимо сохраниться, в настоящий момент является устаревшим), WM_DELETE_WINDOW (удаление окна).
- tkraise (синоним lift) и lower — поднимает (размещает поверх всех других окон) или опускает окно. Методы могут принимать один необязательный аргумент: над/под каким окном разместить текущее.
- grab_set — устанавливает фокус на окно, даже при наличии открытых других окон
- grab_release — снимает монопольное владение фокусом ввода с окна
Эти же методы могут быть использованы для корневого (root) окна.
Пример:
from Tkinter import * def window_deleted(): print u'Окно закрыто' root.quit() # явное указание на выход из программы root=Tk() root.title(u'Пример приложения') root.geometry('500x400+300+200') # ширина=500, высота=400, x=300, y=200 root.protocol('WM_DELETE_WINDOW', window_deleted) # обработчик закрытия окна root.resizable(True, False) # размер окна может быть изменён только по горизонтали root.mainloop()
Таким способом можно предотвратить закрытие окна (например, если закрытие окна приведёт к потере введённых пользователем данных).
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), позволяющее регулировать ширину границы.
- borderwidth — ширина бордюра элемента
- bd — сокращение от borderwidth
- width — задаёт длину элемента в знакоместах.
- show — задает отображаемый символ.
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()
Методы insert, delete и get добавляют, удаляют или извлекают текcт. Первый аргумент — место вставки в виде ‘x.y’, где x – это строка, а y – столбец. Например:
text1.insert(1.0,'Добавить Текстn в начало первой строки') text1.delete('1.0', END) # Удалить все text1.get('1.0', END) # Извлечь все
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. Кроме того в первой или второй строке файла необходимо указать кодировку файла (в комментарии): coding: utf-8. Чаще всего используется формат в стиле текстового редактора emacs:
В Python 3.x кодировку файла можно не указывать, в этом случае по умолчанию предполагается utf-8.
Frame
Виджет Frame (рамка) предназначен для организации виджетов внутри окна. Рассмотрим пример:
from tkinter import * root=Tk() frame1=Frame(root,bg='green',bd=5) frame2=Frame(root,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()
В этом виджете используется уже одна переменная. В зависимости от того, какой пункт выбран, она меняет своё значение. Самое интересное, что если присвоить этой переменной какое-либо значение, поменяется и выбранный виджет. На этом мы прервём изучение типов виджетов (потом мы к ним обязательно вернёмся).
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
Этот виджет даёт возможность пользователю «прокрутить» другой виджет (например текстовое поле) и часто бывает полезен. Использование этого виджета достаточно нетривиально. Необходимо сделать две привязки: command полосы прокрутки привязываем к методу xview/yview виджета, а xscrollcommand/yscrollcommand виджета привязываем к методу set полосы прокрутки.
Рассмотрим на примере:
from tkinter import * root = Tk() text = Text(root, height=3, width=60) text.pack(side='left') scrollbar = Scrollbar(root) scrollbar.pack(side='left') # первая привязка scrollbar['command'] = text.yview # вторая привязка text['yscrollcommand'] = scrollbar.set root.mainloop()
Упаковщики
Упаковщик (менеджер геометрии, менеджер расположения) это специальный механизм, который размещает (упаковывает) виджеты на окне. В Tkinter есть три упаковщика: pack, place, grid. Обратите внимание, что в одном виджете можно использовать только один тип упаковки, при смешивании разных типов упаковки программа, скорее всего, не будет работать.
Разберем каждый из них по порядку:
pack()[6]
Упаковщик pack() является самым интеллектуальным (и самым непредсказуемым). При использовании этого упаковщика с помощью свойства side нужно указать к какой стороне родительского виджета он должен примыкать. Как правило этот упаковщик используют для размещения виджетов друг за другом (слева направо или сверху вниз). Пример:
from tkinter import * root=Tk() button1 = Button(text="1") button2 = Button(text="2") button3 = Button(text="3") button4 = Button(text="4") button5 = Button(text="5") button1.pack(side='left') button2.pack(side='top') button3.pack(side='left') button4.pack(side='bottom') button5.pack(side='right') root.mainloop()
Результат работы можно увидеть на скриншоте справа.
Для создания сложной структуры с использованием этого упаковщика обычно используют Frame, вложенные друг в друга.
- Аргументы
При применении этого упаковщика можно указать следующие аргументы:
- side («left»/»right»/»top»/»bottom») — к какой стороне должен примыкать размещаемый виджет.
- fill (None/»x»/»y»/»both») — необходимо ли расширять пространство предоставляемое виджету.
- expand (True/False) — необходимо ли расширять сам виджет, чтобы он занял всё предоставляемое ему пространство.
- in_ — явное указание в какой родительский виджет должен быть помещён.
- Дополнительные функции
Кроме основной функции у виджетов есть дополнительные методы для работы с упаковщиками.
- pack_configure — синоним для pack.
- pack_slaves (синоним slaves) — возвращает список всех дочерних упакованных виджетов.
- pack_info — возвращает информацию о конфигурации упаковки.
- pack_propagate (синоним propagate) (True/False) — включает/отключает распространении информации о геометрии дочерних виджетов. По умолчанию виджет изменяет свой размер в соответствии с размером своих потомков. Этот метод может отключить такое поведение (pack_propagate(False)). Это может быть полезно, если необходимо, чтобы виджет имел фиксированный размер и не изменял его по прихоти потомков.[7]
- pack_forget (синоним forget) — удаляет виджет и всю информацию о его расположении из упаковщика. Позднее этот виджет может быть снова размещён.
grid()[8]
Этот упаковщик представляет собой таблицу с ячейками, в которые помещаются виджеты.
- Аргументы
- row — номер строки, в который помещаем виджет.
- rowspan — сколько строк занимает виджет
- column — номер столбца, в который помещаем виджет.
- columnspan — сколько столбцов занимает виджет.
- padx / pady — размер внешней границы (бордюра) по горизонтали и вертикали.
- ipadx / ipady — размер внутренней границы (бордюра) по горизонтали и вертикали. Разница между pad и ipad в том, что при указании pad расширяется свободное пространство, а при ipad расширяется помещаемый виджет.
- sticky («n», «s», «e», «w» или их комбинация) — указывает к какой границе «приклеивать» виджет. Позволяет расширять виджет в указанном направлении. Границы названы в соответствии со сторонами света. «n» (север) — верхняя граница, «s» (юг) — нижняя, «w» (запад) — левая, «e» (восток) — правая.
- in_ — явное указание в какой родительский виджет должен быть помещён.
Для каждого виджета указываем, в какой он находится строке, и в каком столбце. Если нужно, указываем, сколько ячеек он занимает (если, например, нам нужно разместить три виджета под одним, необходимо «растянуть» верхний на три ячейки). Пример:
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)
- Дополнительные функции
- grid_configure — синоним для grid.
- grid_slaves (синоним slaves) — см. pack_slaves.
- grid_info — см. pack_info.
- grid_propagate (синоним propagate) — см. pack_propagate.
- grid_forget (синоним forget) — см. pack_forget.
- grid_remove — удаляет виджет из-под управления упаковщиком, но сохраняет информацию об упаковке. Этот метод удобно использовать для временного удаления виджета (см. пример в описании метода destroy).
- grid_bbox (синоним bbox) — возвращает координаты (в пикселях) указанных столбцов и строк.[9]
- grid_location (синоним location) — принимает два аргумента: x и y (в пикселях). Возвращает номер строки и столбца в которые попадают указанные координаты, либо -1 если координаты попали вне виджета.
- grid_size (синоним size) — возвращает размер таблицы в строках и столбцах.
- grid_columnconfigure (синоним columnconfigure) и grid_rowconfigure (синоним rowconfigure) — важные функции для конфигурирования упаковщика. Методы принимают номер строки/столбца и аргументы конфигурации. Список возможных аргументов:
- minsize — минимальная ширина/высота строки/столбца.
- weight — «вес» строки/столбца при увеличении размера виджета. 0 означает, что строка/столбец не будет расширяться. Строка/столбец с «весом» равным 2 будет расширяться вдвое быстрее, чем с весом 1.
- uniform — объединение строк/столбцов в группы. Строки/столбцы имеющие одинаковый параметр uniform будут расширяться строго в соответствии со своим весом.
- pad — размер бордюра. Указывает, сколько пространства будет добавлено к самому большому виджету в строке/столбце.
Пример, текстовый виджет с двумя полосами прокрутки:
from tkinter import * root=Tk() text = Text(wrap=NONE) vscrollbar = Scrollbar(orient='vert', command=text.yview) text['yscrollcommand'] = vscrollbar.set hscrollbar = Scrollbar(orient='hor', command=text.xview) text['xscrollcommand'] = hscrollbar.set # размещаем виджеты text.grid(row=0, column=0, sticky='nsew') vscrollbar.grid(row=0, column=1, sticky='ns') hscrollbar.grid(row=1, column=0, sticky='ew') # конфигурируем упаковщик, чтобы текстовый виджет расширялся root.rowconfigure(0, weight=1) root.columnconfigure(0, weight=1) root.mainloop()
place()[10]
place представляет собой простой упаковщик, позволяющий размещать виджет в фиксированном месте с фиксированным размером. Также он позволяет указывать координаты размещения в относительных единицах для реализации «резинового» размещения. При использовании этого упаковщика, нам необходимо указывать координаты каждого виджета. Например:
Этот упаковщик, хоть и кажется неудобным, предоставляет полную свободу в размещении виджетов на окне.
- Аргументы
- anchor («n», «s», «e», «w», «ne», «nw», «se», «sw» или «center») — какой угол или сторона размещаемого виджета будет указана в аргументах x/y/relx/rely. По умолчанию «nw» — левый верхний
- bordermode («inside», «outside», «ignore») — определяет в какой степени будут учитываться границы при размещении виджета.
- in_ — явное указание в какой родительский виджет должен быть помещён.
- x и y — абсолютные координаты (в пикселях) размещения виджета.
- width и height — абсолютные ширина и высота виджета.
- relx и rely — относительные координаты (от 0.0 до 1.0) размещения виджета.
- relwidth и relheight — относительные ширина и высота виджета.
Относительные и абсолютные координаты (а также ширину и высоту) можно комбинировать. Так например, relx=0.5, x=-2 означает размещение виджета в двух пикселях слева от центра родительского виджета, relheight=1.0, height=-2 — высота виджета на два пикселя меньше высоты родительского виджета.
- Дополнительные функции
place_slaves, place_forget, place_info — см. описание аналогичных методов упаковщика pack.
Привязка событий
«Всё это хорошо» — наверное, подумали вы. — «Но как сделать так, чтобы мои виджеты что-то делали, а не просто красовались на окне?».
command
Для большинства виджетов, реагирующих на действие пользователя, активацию виджета (например нажатие кнопки) можно привязать с использованием опции command. К таким виджетам относятся: Button, Checkbutton, Radiobutton, Spinbox, Scrollbar, Scale. Выше мы уже неоднократно пользовались этим способом:
button = Button(command=callback)
Такой способ является предпочтительным и наиболее удобным способом привязки.
bind()
Метод bind[1] привязывает событие к какому-либо действию (нажатие кнопки мыши, нажатие клавиши на клавиатуре и т.д.). bind принимает три аргумента:
- название события
- функцию, которая будет вызвана при наступлении события
- третий аргумент (необязательный) — строка «+» — означает, что эта привязка добавляется к уже существующим. Если третий аргумент опущен или равен пустой строке — привязка замещает все другие привязки данного события к виджету.
Метод bind возвращает идентификатор привязки, который может быть использован в функции unbind.
Обратите внимание, что если bind привязан к окну верхнего уровня, то Tkinter будет обрабатывать события всех виджетов этого окна (см. также bind_all ниже).
Функция, которая вызывается при наступлении события, должна принимать один аргумент. Это объект класса Event, в котором описано наступившее событие. Объект класса Event имеет следующие атрибуты (в скобках указаны события, для которых этот атрибут установлен):
- serial — серийный номер события (все события)
- num — номер кнопки мыши (ButtonPress, ButtonRelease)
- focus — имеет ли окно фокус (Enter, Leave)
- height и width — ширина и высота окна (Configure, Expose)
- keycode — код нажатой клавиши (KeyPress, KeyRelease)
- state — состояние события (для ButtonPress, ButtonRelease, Enter, KeyPress, КeyRelease, Leave, Motion — в виде числа; для Visibility — в виде строки)
- time — время наступления события (все события)
- x и y — координаты мыши
- x_root и y_root — координаты мыши на экране (ButtonPress, ButtonRelease, KeyPress, KeyRelease, Motion)
- char — набранный на клавиатуре символ (KeyPress, KeyRelease)
- send_event — см. документацию по X/Windows
- keysym — набранный на клавиатуре символ (KeyPress, KeyRelease)
- keysym_num — набранный на клавиатуре символ в виде числа (KeyPress, KeyRelease)
- type — тип события в виде числа (все события)
- widget — виджет, который получил событие (все события)
- delta — изменение при вращении колеса мыши (MouseWheel)
Эта функция может возвращать строки «continue» и «break». Если функция возвращает «continue» то Tkinter продолжит обработку других привязок этого события, если «break» — обработка этого события прекращается. Если функция ничего не возвращает (если возвращает None), то обработка событий продолжается (т.е. это эквивалентно возвращению «continue»).
- Названия событий
Есть три формы названия событий. Самый простой случай это символ ASCII. Так описываются события нажатия клавиш на клавиатуре:
widget.bind("z", callback)
callback вызывается каждый раз, когда будет нажата клавиша «z».
Второй способ длиннее, но позволяет описать больше событий. Он имеет следующий синтаксис:
<modifier-modifier-type-detail>
Название события заключено в угловые скобки. Внутри имеются ноль или более модификаторов, тип события и дополнительная информация (номер нажатой клавиши мыши или символ клавиатуры) Поля разделяются дефисом или пробелом. Пример (привязываем одновременное нажатие Ctrl+Shift+q):
widget.bind("<Control-Shift-KeyPress-q>", callback)
(в данном примере KeyPress можно убрать).
Третий способ позволяет привязывать виртуальные события — события, которые генерируются самим приложением. Такие события можно создавать самим, а потом привязывать их. Имена таких событий помещаются в двойные угловые скобки: <<Paste>>. Есть некоторое количество уже определённых виртуальных событий.
- Список модификаторов
- Return — Enter
- Escape — Esc
- Control — Ctrl
- Alt
- Shift
- Lock
- Extended
- Prior — PgUp
- Next — PgDown
- Button1, B1 — нажата первая (левая) кнопка мыши
- Button2, B2 — вторая (средняя) кнопка мыши
- Button3, B3 — третья (правая)
- Button4, B4 — четвёртая
- Button5, B5 — пятая
- Mod1, M1, Command
- Mod2, M2, Option
- Mod3, M3
- Mod4, M4
- Mod5, M5
- Meta, M
- Double — двойной щелчок мыши (например, <Double-Button-1>)
- Triple — тройной
- Quadruple — четверной
- Типы событий
Здесь перечислены все возможные типы событий, для самых часто используемых дано описание. Более подробно см. man bind.
- Activate, Deactivate
- MouseWheel — прокрутка колесом мыши
- KeyPress, KeyRelease — нажатие и отпускание клавиши на клавиатуре
- ButtonPress, ButtonRelease, Motion — нажатие, отпускание клавиши мыши, движение мышью
- Configure — изменение положения или размера окна
- Map, Unmap — показывание или сокрытие окна (например, в случае сворачивания/разворачивания окна пользователем)
- Visibility
- Expose — событие генерируется, когда необходимо всё окно или его часть перерисовать
- Destroy — закрытие окна
- FocusIn, FocusOut — получение или лишение фокуса
- Enter, Leave — Enter генерируется когда курсор мыши «входит» в окно, Leave — когда «уходит» из окна
- Property
- Colormap
- MapRequest, CirculateRequest, ResizeRequest, ConfigureRequest, Create
- Gravity, Reparent, Circulate
- Клавиатурные символы
Полный список см. man keysyms.
- Примеры
<Button-1> или <1> — нажата левая клавиша мыши.
<Alt-Motion> — движение мышью с нажатой на клавиатуре клавишей Alt.
<Key> — нажатие любой клавиши на клавиатуре.
Пример:
from Tkinter import * root=Tk() def leftclick(event): print u'Вы нажали левую кнопку мыши' def rightclick(event): print u'Вы нажали правую кнопку мыши' button1=Button(root, text=u'Нажми') button1.pack() button1.bind('<Button-1>', leftclick) button1.bind('<Button-3>', rightclick) root.mainloop()
- Дополнительные методы
- bind_all — создаёт привязку для всех виджетов приложения. Отличие от привязки к окну верхнего уровня заключается в том, что в случае привязки к окну привязываются все виджеты этого окна, а этот метод привязывает все виджеты приложения (у приложения может быть несколько окон).
- bind_class — создаёт привязку для всех виджетов данного класса
Пример:
from Tkinter import * def callback(e): print u'Нажата кнопка', e.widget['text'] root=Tk() button1 = Button(root, text='1') button1.pack() button2 = Button(root, text='2') button2.pack() root.bind_class('Button', '<1>', callback) root.mainloop()
- bindtags — позволяет изменить порядок обработки привязок. По умолчанию порядок следующий: виджет, класс, окно, all; где виджет — привязка к виджету (bind), класс — привязка к классу (bind_class), окно — привязка к окну (root.bind), all — привязка всех виджетов (bind_all).
Пример, меняем порядок обработки привязок на обратный:
from Tkinter import * def callback1(e): print 'callback1' def callback2(e): print 'callback2' def callback3(e): print 'callback3' def callback4(e): print 'callback4' root=Tk() button = Button(root) button.pack() button.bind('<1>', callback1) root.bind_class('Button', '<1>', callback2) root.bind('<1>', callback3) root.bind_all('<1>', callback4) button.bindtags(('all', root, 'Button', button)) root.mainloop()
- unbind — отвязать виджет от события. В качестве аргумента принимает идентификатор, полученный от метода bind.
- unbind_all — то же, что и unbind, только для метода bind_all.
- unbind_class — то же, что и unbind, только для метода bind_class.
Изображения
Для работы с изображениями в Tkinter имеется два класса BitmapImage и PhotoImage. BitmapImage представляет собой простое двухцветное изображение, PhotoImage — полноцветное изображение.
BitmapImage
Конструктор класса принимает следующие аргументы:
- background и foreground — цвета фона и переднего плана для изображения. Поскольку изображение двухцветное, то эти параметры определяют соответственно чёрный и белый цвет.
- file и maskfile — пути к файлу с изображением и к маске (изображению, указывающему какие пиксели будут прозрачными).
- data и maskdata — вместо пути к файлу можно указать уже загруженные в память данные изображения. Данная возможность удобна для встраивания изображения в программу.
Пример:
from Tkinter import * data = '''#define image_width 15 #define image_height 15 static unsigned char image_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x30, 0x0c, 0x60, 0x06, 0x60, 0x06, 0xc0, 0x03, 0xc0, 0x03, 0x60, 0x06, 0x60, 0x06, 0x30, 0x0c, 0x38, 0x1c, 0x00, 0x00, 0x00, 0x00 };''' root=Tk() image = BitmapImage(data=data, background='red', foreground='green') button=Button(root, image=image) button.pack() root.mainloop()
PhotoImage
PhotoImage позволяет использовать полноцветное изображение. Кроме того у этого класса есть несколько (достаточно примитивных) методов для работы с изображениями. PhotoImage гарантированно понимает формат GIF.
Аргументы конструктора:
- file — путь к файлу с изображением.
- data — вместо пути к файлу можно указать уже загруженные в память данные изображения. Изображения в формате GIF могут быть закодированы с использованием base64. Данная возможность удобна для встраивания изображения в программу.
- format — явное указание формата изображения.
- width, height — ширина и высота изображения.
- gamma — коррекция гаммы.
- palette — палитра изображения.
ttk
ttk (themed tk) это расширение tcl/tk с новым набором виджетов. В ttk используется новый движок для создания виджетов. Этот движок обладает поддержкой тем и стилей оформления. Благодаря этому виджеты ttk выглядят более естественно в различных операционных системах.
Начиная с версий python 2.7 и 3.1.2 в Tkinter включён модуль для работы с ttk.
В ttk включены следующие виджеты, которые можно использовать вместо соответствующих виджетов tk: Button, Checkbutton, Entry, Frame, Label, LabelFrame, Menubutton, PanedWindow, Radiobutton, Scale и Scrollbar. Кроме того имеется несколько новых виджетов: Combobox, Notebook, Progressbar, Separator, Sizegrip и Treeview.
Поскольку это относительно новая возможность Tkinter, несколько слов об установке этого модуля. Версии python 2.7/3.1.2 и старше уже имеют в своём составе этот модуль. Для использования ttk с более ранними версиями python, его нужно установить самостоятельно. Домашняя страница модуля. В данный момент python-ttk хостится в svn python.org. Модуль представляет собой один файл — ttk.py, который нужно положить в каталог, где его сможет найти python. Прямые ссылки для скачивания: для версии 2.x, для версии 3.x.
С точки зрения программиста главное отличие новых виджетов от старых заключается в том, что у виджетов ttk отсутствуют опции для конфигурирования его внешнего вида. Сравните, например, количество STANDARD OPTIONS для старого и нового виджета button. Конфигурация внешнего вида виджетов ttk осуществляется через темы и стили. В остальном использование виджетов ttk аналогично соответствующим виджетам tk.
ttk имеет четыре встроенных темы: default, classic, alt, clam. Кроме того дополнительно под Windows есть темы winnative, xpnative и vista, а под Mac OS X — aqua.
Style
Style это класс для работы со стилями и темами. Именно этот класс надо использовать для конфигурирования внешнего вида виджетов. Основные методы класса:
- configure
Конфигурирование внешнего вида виджетов. В качестве аргументов принимает название стиля виджета (например «TButton») и список опций конфигурирования. Пример:
style.configure("TButton", padding=6, relief="flat", background="#ccc")
- map
Конфигурирование внешнего вида виджетов в зависимости от их состояний (active, pressed, disabled и т.д.). В качестве аргументов принимает название стиля виджета и список опций конфигурирования, где опции представлены в виде списка. Пример:
style.map("C.TButton", foreground=[('pressed', 'red'), ('active', 'blue')], background=[('pressed', '!disabled', 'black'), ('active', 'white')] )
- lookup
Возвращает соответствующую опцию конфигурирования. Пример:
style.lookup("TButton", "font")
- layout
Изменяет layout (схему) виджета. Виджеты ttk состоят из отдельных элементов, опций конфигурирования и других вложенных layouts. Следующий пример иллюстрирует применение метода layout:
style.layout("TMenubutton", [ ("Menubutton.background", None), ("Menubutton.button", {"children": [("Menubutton.focus", {"children": [("Menubutton.padding", {"children": [("Menubutton.label", {"side": "left", "expand": 1})] })] })] }), ])
- element_create
Создаёт новый элемент темы.
- element_names
Возвращает список элементов текущей темы.
- element_options
Возвращает список опций (конфигурацию), указанного в аргументе элемента.
- theme_create
Создаёт новую тему. Аргументы те же, что и в theme_settings.
- theme_settings
Конфигурирует существующую тему. Первый аргумент — название темы, второй аргумент — словарь, ключами которого являются названия стилей (TButton и т.п.), а значениями — layout соответствующего стиля.
- theme_names
Возвращает список доступных тем.
- theme_use
Изменяет текущую тему на указанную в аргументе.
Combobox
Виджет Combobox предназначен для отображения списка значений, их выбора или изменения пользователем. В версии tk ему подобен виджет Listbox. Разница заключается в том, что Combobox имеет возможность сворачиваться подобно свитку, а Listbox будет отображаться всегда открытым.
Что бы отобразить Combobox с заранее заданными значениями в форме, достаточно сделать следующее:
import tkinter as tk import tkinter.ttk as ttk root = tk.Tk() frame = tk.Frame(root) frame.grid() combobox = ttk.Combobox(frame,values = [u"ОДИН",u"ДВА",u"ТРИ"],height=3) #frame - задает родительский виджет, на его территории будет располагаться Combobox #values - задает набор значений, которые будут содержаться в Combobox изначально #height - задает высоту выпадающего списка. Если число элементов списка меньше 11, то можно не задавать. #Если не задано при количестве элементов больше 10, то с правой стороны появится полоса прокрутки. #Если в нашем примере задать значение height меньше трех, то с правой стороны появится полоса прокрутки, #но она будет недоступна, а все элементы будут отображаться одновременно. combobox.set(u"ОДИН")#с помощью этой строчки мы установим Combobox в значение ОДИН изначально combobox.grid(column=0,row=0)#Позиционируем Combobox на форме root.mainloop()
Progressbar
Виджет отображает уровень загрузки.
- length — длина полосы.
- start
Запускает бесконечный цикл загрузки. Шаг длиною 1 выполняется один раз в указанное время (в миллисекундах).
- stop
Останавливает цикл загрузки.
- step
Продвигает загрузку на заданное количество шагов.
import tkinter as tk import tkinter.ttk as ttk root = tk.Tk() pb = ttk.Progressbar(root, length=100) pb.pack() pb.start(100) root.mainloop()
Примечания
- ↑ http://www.tcl.tk/man/tcl8.5/TkCmd/grab.htm
- ↑ http://www.tcl.tk/man/tcl8.5/TkCmd/focus.htm
- ↑ http://www.tcl.tk/man/tcl8.5/TclCmd/after.htm
- ↑ http://www.tcl.tk/man/tcl8.5/TclCmd/update.htm
- ↑ http://www.tcl.tk/man/tcl8.5/TkCmd/toplevel.htm
- ↑ http://www.tcl.tk/man/tcl8.5/TkCmd/pack.htm
- ↑ http://www.tcl.tk/man/tcl8.5/TkCmd/pack.htm#M28
- ↑ http://www.tcl.tk/man/tcl8.5/TkCmd/grid.htm
- ↑ http://www.tcl.tk/man/tcl8.5/TkCmd/grid.htm#M7
- ↑ http://www.tcl.tk/man/tcl8.5/TkCmd/place.htm
Ссылки
- An Introduction to Tkinter (англ.) — хорошее дополнение к документации
- Роман Сузи. Tkinter в рамках интерактивного курса «Язык программирования Python»
- Несколько статей на русском
The end
В этом уроке мы узнаем, как разрабатывать графические пользовательские интерфейсы, с помощью разбора некоторых примеров графического интерфейса Python с использованием библиотеки Tkinter.
Библиотека Tkinter установлена в Python в качестве стандартного модуля, поэтому нам не нужно устанавливать что-либо для его использования. Tkinter — очень мощная библиотека. Если вы уже установили Python, можете использовать IDLE, который является интегрированной IDE, поставляемой в Python, эта IDE написана с использованием Tkinter. Звучит круто!
Мы будем использовать Python 3.7 поэтому, если вы все еще используете Python 2.x, настоятельно рекомендуем перейти на Python 3.x, если вы не в курсе нюансов изменения языка, с целью, чтобы вы могли настроить код для запуска без ошибок.
Давайте предположим, что у вас уже есть базовые знания по Python, которые помогут понять что мы будем делать.
Мы начнем с создания окна, в котором мы узнаем, как добавлять виджеты, такие, как кнопки, комбинированные поля и т. д. После этого поэкспериментируем со своими свойствами, поэтому предлагаю начать.
Создание своего первого графического интерфейса
Для начала, следует импортировать Tkinter и создать окно, в котором мы зададим его название:
from tkinter import *
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.mainloop()
Результат будет выглядеть следующим образом:
Прекрасно! Наше приложение работает.
Последняя строка вызывает функцию mainloop
. Эта функция вызывает бесконечный цикл окна, поэтому окно будет ждать любого взаимодействия с пользователем, пока не будет закрыто.
В случае, если вы забудете вызвать функцию mainloop
, для пользователя ничего не отобразится.
Создание виджета Label
Чтобы добавить текст в наш предыдущий пример, мы создадим lbl
, с помощью класса Label
, например:
lbl = Label(window, text="Привет")
Затем мы установим позицию в окне с помощью функции grid
и укажем ее следующим образом:
lbl.grid(column=0, row=0)
Полный код, будет выглядеть следующим образом:
from tkinter import *
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
lbl = Label(window, text="Привет")
lbl.grid(column=0, row=0)
window.mainloop()
И вот как будет выглядеть результат:
Если функция grid
не будет вызвана, текст не будет отображаться.
Настройка размера и шрифта текста
Вы можете задать шрифт текста и размер. Также можно изменить стиль шрифта. Для этого передайте параметр font
таким образом:
lbl = Label(window, text="Привет", font=("Arial Bold", 50))
Обратите внимание, что параметр font
может быть передан любому виджету, для того, чтобы поменять его шрифт, он применяется не только к Label
.
Отлично, но стандартное окно слишком мало. Как насчет настройки размера окна?
Настройка размеров окна приложения
Мы можем установить размер окна по умолчанию, используя функцию geometry
следующим образом:
window.geometry('400x250')
В приведенной выше строке устанавливается окно шириной до 400 пикселей и высотой до 250 пикселей.
Попробуем добавить больше виджетов GUI, например, кнопки и посмотреть, как обрабатывается нажатие кнопок.
Добавление виджета Button
Начнем с добавления кнопки в окно. Кнопка создается и добавляется в окно так же, как и метка:
btn = Button(window, text="Не нажимать!")
btn.grid(column=1, row=0)
Наш код будет выглядеть вот так:
from tkinter import *
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
lbl = Label(window, text="Привет", font=("Arial Bold", 50))
lbl.grid(column=0, row=0)
btn = Button(window, text="Не нажимать!")
btn.grid(column=1, row=0)
window.mainloop()
Результат будет следующим:
Обратите внимание, что мы помещаем кнопку во второй столбец окна, что равно 1. Если вы забудете и поместите кнопку в том же столбце, который равен 0, он покажет только кнопку.
Изменение цвета текста и фона у Button
Вы можете поменять цвет текста кнопки или любого другого виджета, используя свойство fg
.
Кроме того, вы можете поменять цвет фона любого виджета, используя свойство bg
.
btn = Button(window, text="Не нажимать!", bg="black", fg="red")
Теперь, если вы попытаетесь щелкнуть по кнопке, ничего не произойдет, потому что событие нажатия кнопки еще не написано.
Кнопка Click
Для начала, мы запишем функцию, которую нужно выполнить при нажатии кнопки:
def clicked():
lbl.configure(text="Я же просил...")
Затем мы подключим ее с помощью кнопки, указав следующую функцию:
btn = Button(window, text="Не нажимать!", command=clicked)
Обратите внимание: мы пишем clicked
, а не clicked()
с круглыми скобками. Теперь полный код будет выглядеть так:
from tkinter import *
def clicked():
lbl.configure(text="Я же просил...")
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
lbl = Label(window, text="Привет", font=("Arial Bold", 50))
lbl.grid(column=0, row=0)
btn = Button(window, text="Не нажимать!", command=clicked)
btn.grid(column=1, row=0)
window.mainloop()
При нажатии на кнопку, результат, как и ожидалось, будет выглядеть следующим образом:
Круто!
Получение ввода с использованием класса Entry (текстовое поле Tkinter)
В предыдущих примерах GUI Python мы ознакомились со способами добавления простых виджетов, а теперь попробуем получить пользовательский ввод, используя класс Tkinter Entry
(текстовое поле Tkinter).
Вы можете создать текстовое поле с помощью класса Tkinter Entry
следующим образом:
txt = Entry(window, width=10)
Затем вы можете добавить его в окно, используя функцию grid
.
Наше окно будет выглядеть так:
from tkinter import *
def clicked():
lbl.configure(text="Я же просил...")
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
lbl = Label(window, text="Привет")
lbl.grid(column=0, row=0)
txt = Entry(window,width=10)
txt.grid(column=1, row=0)
btn = Button(window, text="Не нажимать!", command=clicked)
btn.grid(column=2, row=0)
window.mainloop()
Полученный результат будет выглядеть так:
Теперь, если вы нажмете кнопку, она покажет то же самое старое сообщение, но что же будет с отображением введенного текста в виджет Entry
?
Во-первых, вы можете получить текст ввода, используя функцию get
. Мы можем записать код для выбранной функции таким образом:
def clicked():
res = "Привет {}".format(txt.get())
lbl.configure(text=res)
Если вы нажмете на кнопку — появится текст «Привет » вместе с введенным текстом в виджете записи. Вот полный код:
from tkinter import *
def clicked():
res = "Привет {}".format(txt.get())
lbl.configure(text=res)
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
lbl = Label(window, text="Привет")
lbl.grid(column=0, row=0)
txt = Entry(window,width=10)
txt.grid(column=1, row=0)
btn = Button(window, text="Клик!", command=clicked)
btn.grid(column=2, row=0)
window.mainloop()
Запустите вышеуказанный код и проверьте результат:
Прекрасно!
Каждый раз, когда мы запускаем код, нам нужно нажать на виджет ввода, чтобы настроить фокус на ввод текста, но как насчет автоматической настройки фокуса?
Установка фокуса виджета ввода
Здесь все очень просто, ведь все, что нам нужно сделать, — это вызвать функцию focus
:
txt.focus()
Когда вы запустите свой код, вы заметите, что виджет ввода в фокусе, который дает возможность сразу написать текст.
Отключить виджет ввода
Чтобы отключить виджет ввода, отключите свойство состояния:
txt = Entry(window,width=10, state='disabled')
Теперь вы не сможете ввести какой-либо текст.
Добавление виджета Combobox
Чтобы добавить виджет поля с выпадающем списком, используйте класс Combobox
из ttk
следующим образом:
from tkinter.ttk import Combobox
combo = Combobox(window)
Затем добавьте свои значения в поле со списком.
from tkinter import *
from tkinter.ttk import Combobox
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
combo = Combobox(window)
combo['values'] = (1, 2, 3, 4, 5, "Текст")
combo.current(1) # установите вариант по умолчанию
combo.grid(column=0, row=0)
window.mainloop()
Как видите с примера, мы добавляем элементы combobox
, используя значения tuple
.
Чтобы установить выбранный элемент, вы можете передать индекс нужного элемента текущей функции.
Чтобы получить элемент select
, вы можете использовать функцию get
вот таким образом:
combo.get()
Добавление виджета Checkbutton (чекбокса)
С целью создания виджета checkbutton
, используйте класс Checkbutton
:
from tkinter.ttk import Checkbutton
chk = Checkbutton(window, text='Выбрать')
Кроме того, вы можете задать значение по умолчанию, передав его в параметр var
в Checkbutton
:
from tkinter import *
from tkinter.ttk import Checkbutton
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
chk_state = BooleanVar()
chk_state.set(True) # задайте проверку состояния чекбокса
chk = Checkbutton(window, text='Выбрать', var=chk_state)
chk.grid(column=0, row=0)
window.mainloop()
Посмотрите на результат:
Установка состояния Checkbutton
Здесь мы создаем переменную типа BooleanVar
, которая не является стандартной переменной Python, это переменная Tkinter, затем передаем ее классу Checkbutton
, чтобы установить состояние чекбокса как True
в приведенном выше примере.
Вы можете установить для BooleanVar
значение false, что бы чекбокс не был отмечен.
Так же, используйте IntVar
вместо BooleanVar
и установите значения 0 и 1.
chk_state = IntVar()
chk_state.set(0) # False
chk_state.set(1) # True
Эти примеры дают тот же результат, что и BooleanVar
.
Добавление виджетов Radio Button
Чтобы добавить radio кнопки, используйте класс RadioButton
:
rad1 = Radiobutton(window,text='Первый', value=1)
Обратите внимание, что вы должны установить value
для каждой radio кнопки с уникальным значением, иначе они не будут работать.
from tkinter import *
from tkinter.ttk import Radiobutton
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
rad1 = Radiobutton(window, text='Первый', value=1)
rad2 = Radiobutton(window, text='Второй', value=2)
rad3 = Radiobutton(window, text='Третий', value=3)
rad1.grid(column=0, row=0)
rad2.grid(column=1, row=0)
rad3.grid(column=2, row=0)
window.mainloop()
Результатом вышеприведенного кода будет следующий:
Кроме того, вы можете задать command
любой из этих кнопок для определенной функции. Если пользователь нажимает на такую кнопку, она запустит код функции.
Вот пример:
rad1 = Radiobutton(window,text='Первая', value=1, command=clicked)
def clicked():
# Делайте, что нужно
Достаточно легко!
Получение значения Radio Button (Избранная Radio Button)
Чтобы получить текущую выбранную radio кнопку или ее значение, вы можете передать параметр переменной и получить его значение.
from tkinter import *
from tkinter.ttk import Radiobutton
def clicked():
lbl.configure(text=selected.get())
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
selected = IntVar()
rad1 = Radiobutton(window,text='Первый', value=1, variable=selected)
rad2 = Radiobutton(window,text='Второй', value=2, variable=selected)
rad3 = Radiobutton(window,text='Третий', value=3, variable=selected)
btn = Button(window, text="Клик", command=clicked)
lbl = Label(window)
rad1.grid(column=0, row=0)
rad2.grid(column=1, row=0)
rad3.grid(column=2, row=0)
btn.grid(column=3, row=0)
lbl.grid(column=0, row=1)
window.mainloop()
Каждый раз, когда вы выбираете radio button, значение переменной будет изменено на значение кнопки.
Добавление виджета ScrolledText (текстовая область Tkinter)
Чтобы добавить виджет ScrolledText
, используйте класс ScrolledText
:
from tkinter import scrolledtext
txt = scrolledtext.ScrolledText(window,width=40,height=10)
Здесь нужно указать ширину и высоту ScrolledText
, иначе он заполнит все окно.
from tkinter import *
from tkinter import scrolledtext
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
txt = scrolledtext.ScrolledText(window, width=40, height=10)
txt.grid(column=0, row=0)
window.mainloop()
Результат:
Настройка содержимого Scrolledtext
Используйте метод insert
, чтобы настроить содержимое Scrolledtext
:
txt.insert(INSERT, 'Текстовое поле')
Удаление/Очистка содержимого Scrolledtext
Чтобы очистить содержимое данного виджета, используйте метод delete
:
txt.delete(1.0, END) # мы передали координаты очистки
Отлично!
Создание всплывающего окна с сообщением
Чтобы показать всплывающее окно с помощью Tkinter, используйте messagebox
следующим образом:
from tkinter import messagebox
messagebox.showinfo('Заголовок', 'Текст')
Довольно легко! Давайте покажем окно сообщений при нажатии на кнопку пользователем.
from tkinter import *
from tkinter import messagebox
def clicked():
messagebox.showinfo('Заголовок', 'Текст')
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
btn = Button(window, text='Клик', command=clicked)
btn.grid(column=0, row=0)
window.mainloop()
Когда вы нажмете на кнопку, появится информационное окно.
Показ сообщений о предупреждениях и ошибках
Вы можете показать предупреждающее сообщение или сообщение об ошибке таким же образом. Единственное, что нужно изменить—это функция сообщения.
messagebox.showwarning('Заголовок', 'Текст') # показывает предупреждающее сообщение
messagebox.showerror('Заголовок', 'Текст') # показывает сообщение об ошибке
Показ диалоговых окон с выбором варианта
Чтобы показать пользователю сообщение “да/нет”, вы можете использовать одну из следующих функций messagebox
:
from tkinter import messagebox
res = messagebox.askquestion('Заголовок', 'Текст')
res = messagebox.askyesno('Заголовок', 'Текст')
res = messagebox.askyesnocancel('Заголовок', 'Текст')
res = messagebox.askokcancel('Заголовок', 'Текст')
res = messagebox.askretrycancel('Заголовок', 'Текст')
Вы можете выбрать соответствующий стиль сообщения согласно вашим потребностям. Просто замените строку функции showinfo
на одну из предыдущих и запустите скрипт. Кроме того, можно проверить, какая кнопка нажата, используя переменную результата.
Если вы кликнете OK, yes или retry, значение станет True, а если выберете no или cancel, значение будет False.
Единственной функцией, которая возвращает одно из трех значений, является функция askyesnocancel
; она возвращает True/False/None.
Добавление SpinBox (Виджет спинбокс)
Для создания виджета спинбокса, используйте класс Spinbox
:
spin = Spinbox(window, from_=0, to=100)
Таким образом, мы создаем виджет Spinbox
, и передаем параметры from
и to
, чтобы указать диапазон номеров.
Кроме того, вы можете указать ширину виджета с помощью параметра width
:
spin = Spinbox(window, from_=0, to=100, width=5)
Проверим пример полностью:
from tkinter import *
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
spin = Spinbox(window, from_=0, to=100, width=5)
spin.grid(column=0, row=0)
window.mainloop()
Вы можете указать числа для Spinbox
, вместо использования всего диапазона следующим образом:
spin = Spinbox(window, values=(3, 8, 11), width=5)
Виджет покажет только эти 3 числа: 3, 8 и 11.
Задать значение по умолчанию для Spinbox
В случае, если вам нужно задать значение по умолчанию для Spinbox, вы можете передать значение параметру textvariable
следующим образом:
var = IntVar()
var.set(36)
spin = Spinbox(window, from_=0, to=100, width=5, textvariable=var)
Теперь, если вы запустите программу, она покажет 36 как значение по умолчанию для Spinbox.
Добавление виджета Progressbar
Чтобы создать данный виджет, используйте класс progressbar
:
from tkinter.ttk import Progressbar
bar = Progressbar(window, length=200)
Установите значение progressbar таким образом:
bar['value'] = 70
Вы можете установить это значение на основе любого процесса или при выполнении задачи.
Изменение цвета Progressbar
Изменение цвета Progressbar немного сложно. Сначала нужно создать стиль и задать цвет фона, а затем настроить созданный стиль на Progressbar. Посмотрите следующий пример:
from tkinter import *
from tkinter.ttk import Progressbar
from tkinter import ttk
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
style = ttk.Style()
style.theme_use('default')
style.configure("black.Horizontal.TProgressbar", background='black')
bar = Progressbar(window, length=200, style='black.Horizontal.TProgressbar')
bar['value'] = 70
bar.grid(column=0, row=0)
window.mainloop()
И в результате вы получите следующее:
Добавление поля загрузки файла
Для добавления поля с файлом, используйте класс filedialog
:
from tkinter import filedialog
file = filedialog.askopenfilename()
После того, как вы выберете файл, нажмите “Открыть”; переменная файла будет содержать этот путь к файлу. Кроме того, вы можете запросить несколько файлов:
files = filedialog.askopenfilenames()
Указание типа файлов (расширение фильтра файлов)
Возможность указания типа файлов доступна при использовании параметра filetypes
, однако при этом важно указать расширение в tuples.
file = filedialog.askopenfilename(filetypes = (("Text files","*.txt"),("all files","*.*")))
Вы можете запросить каталог, используя метод askdirectory
:
dir = filedialog.askdirectory()
Вы можете указать начальную директорию для диалогового окна файла, указав initialdir
следующим образом:
from os import path
file = filedialog.askopenfilename(initialdir= path.dirname(__file__))
Легко!
Добавление панели меню
Для добавления панели меню, используйте класс menu
:
from tkinter import Menu
menu = Menu(window)
menu.add_command(label='Файл')
window.config(menu=menu)
Сначала мы создаем меню, затем добавляем наш первый пункт подменю. Вы можете добавлять пункты меню в любое меню с помощью функции add_cascade()
таким образом:
menu.add_cascade(label='Автор', menu=new_item)
Наш код будет выглядеть так:
from tkinter import *
from tkinter import Menu
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
menu = Menu(window)
new_item = Menu(menu)
new_item.add_command(label='Новый')
menu.add_cascade(label='Файл', menu=new_item)
window.config(menu=menu)
window.mainloop()
Таким образом, вы можете добавить столько пунктов меню, сколько захотите.
from tkinter import *
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
menu = Menu(window)
new_item = Menu(menu)
new_item.add_command(label='Новый')
new_item.add_separator()
new_item.add_command(label='Изменить')
menu.add_cascade(label='Файл', menu=new_item)
window.config(menu=menu)
window.mainloop()
Теперь мы добавляем еще один пункт меню “Изменить” с разделителем меню. Вы можете заметить пунктирную линию в начале, если вы нажмете на эту строку, она отобразит пункты меню в небольшом отдельном окне.
Можно отключить эту функцию, с помощью tearoff
подобным образом:
new_item = Menu(menu, tearoff=0)
Просто отредактируйте new_item
, как в приведенном выше примере и он больше не будет отображать пунктирную линию.
Вы так же можете ввести любой код, который работает, при нажатии пользователем на любой элемент меню, задавая свойство команды.
new_item.add_command(label='Новый', command=clicked)
Добавление виджета Notebook (Управление вкладкой)
Для удобного управления вкладками реализуйте следующее:
- Для начала, создается элемент управления вкладкой, с помощью класса
Notebook
. - Создайте вкладку, используя класс
Frame
. - Добавьте эту вкладку в элемент управления вкладками.
- Запакуйте элемент управления вкладкой, чтобы он стал видимым в окне.
from tkinter import *
from tkinter import ttk
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
tab_control = ttk.Notebook(window)
tab1 = ttk.Frame(tab_control)
tab_control.add(tab1, text='Первая')
tab_control.pack(expand=1, fill='both')
window.mainloop()
Таким образом, вы можете добавлять столько вкладок, сколько нужно.
Добавление виджетов на вкладку
После создания вкладок вы можете поместить виджеты внутри этих вкладок, назначив родительское свойство нужной вкладке.
from tkinter import *
from tkinter import ttk
window = Tk()
window.title("Добро пожаловать в приложение PythonRu")
window.geometry('400x250')
tab_control = ttk.Notebook(window)
tab1 = ttk.Frame(tab_control)
tab2 = ttk.Frame(tab_control)
tab_control.add(tab1, text='Первая')
tab_control.add(tab2, text='Вторая')
lbl1 = Label(tab1, text='Вкладка 1')
lbl1.grid(column=0, row=0)
lbl2 = Label(tab2, text='Вкладка 2')
lbl2.grid(column=0, row=0)
tab_control.pack(expand=1, fill='both')
window.mainloop()
Добавление интервала для виджетов (Заполнение)
Вы можете добавить отступы для элементов управления, чтобы они выглядели хорошо организованными с использованием свойств padx
иpady
.
Передайте padx
и pady
любому виджету и задайте значение.
lbl1 = Label(tab1, text= 'label1', padx=5, pady=5)
Это очень просто!
В этом уроке мы увидели много примеров GUI Python с использованием библиотеки Tkinter. Так же рассмотрели основные аспекты разработки графического интерфейса Python. Не стоит на этом останавливаться. Нет учебника или книги, которая может охватывать все детали. Надеюсь, эти примеры были полезными для вас.
Python предоставляет стандартную библиотеку Tkinter для создания графического пользовательского интерфейса для настольных приложений.
Разработка настольных приложений с помощью python Tkinter – не сложная задача. Пустое окно верхнего уровня Tkinter можно создать, выполнив следующие действия:
- Импортировать модуль Tkinter.
- Создайте главное окно приложения.
- Добавьте в окно виджеты, такие как метки, кнопки, рамки и т. д.
- Вызовите основной цикл событий, чтобы действия могли отображаться на экране компьютера пользователя.
Пример:
# !/usr/bin/python3 from tkinter import * #creating the application main window. top = Tk() #Entering the event main loop top.mainloop()
Вывод:
Виджеты
Существуют различные виджеты, такие как button, canvas, checkbutton, entry и т. д., которые используются для создания приложений с графическим интерфейсом пользователя Python.
№ | Виджет | Описание |
---|---|---|
1 | Button | Виджет кнопки используется для добавления различных типов кнопок в приложение Python. |
2 | Canvas | Этот виджет используется для рисования на холсте в окне. |
3 | Checkbutton | Используется для отображения кнопки-флажка в окне. |
4 | Entry | Виджет ввода используется для отображения однострочного текстового поля. Обычно он используется для принятия пользовательских значений. |
5 | Frame | Этот виджет можно определить как контейнер, в который можно добавить и организовать другой виджет. |
6 | Label | Метка – это текст, используемый для отображения некоторого сообщения или информации о других виджетах. |
7 | ListBox | Виджет ListBox используется для отображения пользователю списка параметров. |
8 | Menubutton | Menubutton используется для отображения пунктов меню пользователю. |
9 | Menu | Он используется для добавления пользователю пунктов меню. |
10 | Message | Виджет сообщения используется для отображения окна сообщения пользователю. |
11 | Radiobutton | Радиокнопка отличается от кнопки-флажка. Здесь пользователю предоставляются различные варианты, и пользователь может выбрать среди них только один вариант. |
12 | Scale | Используется для предоставления пользователю ползунка. |
13 | Scrollbar | Он предоставляет пользователю полосу прокрутки, чтобы пользователь мог прокручивать окно вверх и вниз. |
14 | Text | Он отличается от Entry, поскольку предоставляет пользователю многострочное текстовое поле, чтобы пользователь мог писать текст и редактировать текст внутри него. |
15 | Toplevel | Используется для создания отдельного оконного контейнера. |
16 | Spinbox | Это виджет ввода, используемый для выбора вариантов значений. |
17 | PanedWindow | Похож на виджет-контейнер, который содержит горизонтальные или вертикальные панели. |
18 | LabelFrame | LabelFrame – это виджет, который действует как контейнер. |
19 | MessageBox | Этот модуль используется для отображения окна сообщения в настольных приложениях. |
Геометрия
Геометрия Tkinter определяет метод, с помощью которого виджеты отображаются на дисплее. Python Tkinter предоставляет следующие геометрические методы.
- Метод pack().
- Метод grid().
- Метод place().
Давайте подробно обсудим каждый из них.
Метод pack() используется для организации виджета в блоке. Виджетами позиций, добавленными в приложение Python с помощью метода pack(), можно управлять с помощью различных параметров, указанных в вызове метода.
Однако элементов управления меньше, а виджеты обычно добавляются менее организованно.
Синтаксис использования pack() приведен ниже:
widget.pack(options)
Список возможных параметров, которые можно передать в pack(), приведен ниже.
- expand: если для параметра «expand» задано значение «истина», виджет расширяется, заполняя любое пространство.
- Fill: по умолчанию для заливки установлено значение NONE. Однако мы можем установить для него значение X или Y, чтобы определить, есть ли в виджете лишнее пространство.
- size: представляет сторону родительского элемента, с которой виджет должен быть размещен в окне.
Пример:
# !/usr/bin/python3 from tkinter import * parent = Tk() redbutton = Button(parent, text = "Red", fg = "red") redbutton.pack( side = LEFT) greenbutton = Button(parent, text = "Black", fg = "black") greenbutton.pack( side = RIGHT ) bluebutton = Button(parent, text = "Blue", fg = "blue") bluebutton.pack( side = TOP ) blackbutton = Button(parent, text = "Green", fg = "red") blackbutton.pack( side = BOTTOM) parent.mainloop()
Вывод:
Метод Python Tkinter grid()
Менеджер геометрии grid() организует виджеты в табличной форме. Мы можем указать строки и столбцы в качестве параметров при вызове метода. Мы также можем указать диапазон столбцов (ширину) или диапазон строк (высоту) виджета.
Это более организованный способ размещения виджетов в приложении Python. Синтаксис использования grid() приведен ниже:
widget.grid(options)
Список возможных параметров, которые можно передать внутри метода grid():
- Column
Номер столбца, в который будет помещен виджет. Крайний левый столбец представлен 0. - Columnspan
Ширина виджета. Он представляет количество столбцов, до которых столбец расширяется. - ipadx, ipadyПредставляет количество пикселей для заполнения виджета внутри границы.
- padx, pady
Представляет количество пикселей для размещения виджета за пределами его границы. - row
Номер строки, в которую должен быть помещен виджет. Самая верхняя строка представлена 0. - rowspan
Высота виджета, то есть номер строки, до которой расширяется виджет. - Sticky
Если ячейка больше, чем виджет, то используется Sticky, чтобы указать положение виджета внутри ячейки. Это может быть соединение букв, представляющих позицию виджета. Это может быть N, E, W, S, NE, NW, NS, EW, ES.
Пример:
# !/usr/bin/python3 from tkinter import * parent = Tk() name = Label(parent,text = "Name").grid(row = 0, column = 0) e1 = Entry(parent).grid(row = 0, column = 1) password = Label(parent,text = "Password").grid(row = 1, column = 0) e2 = Entry(parent).grid(row = 1, column = 1) submit = Button(parent, text = "Submit").grid(row = 4, column = 0) parent.mainloop()
Вывод:
Метод Python Tkinter place()
Менеджер place() упорядочивает виджеты по определенным координатам x и y.
Синтаксис:
widget.place(options)
Список возможных вариантов приведен ниже:
- Anchor: он представляет собой точное положение виджета в контейнере. Значение по умолчанию (direction) – NW (левый верхний угол).
- bordermode: значение по умолчанию для типа границы – INSIDE, что означает игнорирование родительского элемента внутри границы. Другой вариант – OUTSIDE.
- height, width: это высота и ширина в пикселях.
- relheight, relwidth: представлен как число с плавающей запятой между 0,0 и 1,0, указывающее долю высоты и ширины родительского элемента.
- relx, rely: представлен в виде числа с плавающей запятой между 0,0 и 1,0, которое представляет собой смещение в горизонтальном и вертикальном направлениях.
- x, y: это относится к горизонтальному и вертикальному смещению в пикселях.
Пример:
# !/usr/bin/python3 from tkinter import * top = Tk() top.geometry("400x250") name = Label(top, text = "Name").place(x = 30,y = 50) email = Label(top, text = "Email").place(x = 30, y = 90) password = Label(top, text = "Password").place(x = 30, y = 130) e1 = Entry(top).place(x = 80, y = 50) e2 = Entry(top).place(x = 80, y = 90) e3 = Entry(top).place(x = 95, y = 130) top.mainloop()
Вывод:
Прежде чем изучать Tkinter, вы должны иметь базовые знания Python. Наше руководство по Python Tkinter разработано, чтобы помочь новичкам и профессионалам.
Изучаю Python вместе с вами, читаю, собираю и записываю информацию опытных программистов.