Что найти?

Разработка графического интерфейса с помощью Tkinter в Python

/
/

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

Создание первого окна

Как упоминалось ранее, Tkinter доступен со стандартными установками Python, поэтому независимо от вашей операционной системы создание вашего первого окна должно быть очень быстрым. Все, что вам нужно, это 3 строки кода:

import tkinter

root = tkinter.Tk()

root.mainloop()

Вывод:

Создание первого окна

После импорта пакета tkinter в строке 1, в строке 3 мы создаем виджет главного (корневого) окна приложения. Чтобы программа работала должным образом, в нашем интерфейсе должен быть только один виджет корневого окна, и, поскольку все остальные виджеты будут ниже в иерархии, чем корневые, он должен быть создан перед любыми другими виджетами.

В строке 5 мы инициализируем главный цикл корня. Благодаря этой строке окно остается в цикле, который ожидает событий (например, взаимодействия с пользователем) и соответствующим образом обновляет интерфейс. Цикл заканчивается, когда пользователь закрывает окно или вызывается метод quit().

Добавление простых виджетов в корневое окно

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

На втором этапе мы должны использовать один из доступных методов для размещения нового виджета внутри другого уже существующего виджета (родительского). Самый простой виджет, который вы можете поместить в свой интерфейс Tkinter, – это метка, которая просто отображает некоторый текст. В следующем примере создается простой виджет метки:

import tkinter

root = tkinter.Tk()

simple_label = tkinter.Label(root, text="Easy, right?")

simple_label.pack()

root.mainloop()

Вывод:

Добавление простых виджетов в корневое окно

Мы создаем экземпляр класса Label в строке 5 приведенного выше кода. В первом аргументе мы указываем на желаемый родительский виджет метки, которым в этом примере является наше корневое окно. Во втором аргументе мы указываем текст, который должна отображать метка.

Затем в строке 7 мы применяем метод ориентации нашей метки внутри корневого окна. Самый простой метод ориентирования виджетов, который предлагает Tkinter, – это pack(). Метка – единственный виджет внутри окна, поэтому он просто отображается в середине окна.

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

Добавление функциональной кнопки

Теперь давайте добавим то, с чем пользователь может взаимодействовать. Самый очевидный выбор – простая кнопка. Давайте поместим кнопку в наше окно, которая даст нам дополнительный способ закрыть наше окно.

import tkinter

root = tkinter.Tk()

root.title("Hello!")

simple_label = tkinter.Label(root, text="Easy, right?")
closing_button = tkinter.Button(root, text="Close window", command=root.destroy)

simple_label.pack()
closing_button.pack()

root.mainloop()

Вывод:

Добавление функциональной кнопки

В строке 8 мы создаем экземпляр класса Button аналогично тому, как мы создавали метку. Однако, как вы, вероятно, видите, мы добавили аргумент команды, в котором мы сообщаем программе, что должно произойти после нажатия кнопки. В этом случае вызывается метод destroy() root, который закрывает наше окно при выполнении.

В строках 10 и 11 мы снова используем метод pack(). На этот раз мы можем понять это немного лучше, поскольку теперь мы используем его для размещения двух виджетов внутри окна. В зависимости от порядка, в котором мы упаковываем наши виджеты, метод просто помещает их один поверх другого по центру по горизонтали. Высота и ширина окна подстраиваются под размеры виджетов.

Вы, наверное, заметили еще одну новую строчку. В строке 5 мы указываем заголовок корневого окна. К сожалению, самый широкий виджет нашего интерфейса недостаточно широк, чтобы заголовок окна стал видимым.

Управление размером окна

Давайте взглянем на три новые строки, которые позволят нам легко изменять размер нашего окна.

import tkinter

root = tkinter.Tk()

root.title("Hello!")

root.resizable(width="false", height="false")

root.minsize(width=300, height=50)
root.maxsize(width=300, height=50)

simple_label = tkinter.Label(root, text="Easy, right?")
closing_button = tkinter.Button(root, text="Close window", command=root.destroy)

simple_label.pack()
closing_button.pack()

root.mainloop()

Вывод:

Разработка графического интерфейса с помощью Tkinter в Python

В строке 7 мы определяем, должен ли пользователь программы изменять ширину и высоту окна. В этом случае для обоих аргументов установлено значение «false», поэтому размер окна зависит только от нашего кода. Если бы не строки 9 и 10, это зависело бы от размеров виджетов, ориентированных внутри окна.

Однако в этом примере мы используем методы root minsize и maxsize для управления максимальными и минимальными значениями ширины и высоты нашего окна. Здесь мы точно определяем, насколько широким и высоким должно быть окно, но я рекомендую вам поиграть с этими тремя строками, чтобы увидеть, как изменение размера работает в зависимости от размера наших виджетов и от того, какие минимальные и максимальные значения мы определяем.

Подробнее об ориентации виджета

Как вы, наверное, уже заметили, использование метода pack() не дает нам слишком много контроля над тем, где находятся виджеты после их упаковки в родительские контейнеры. Нельзя сказать, что метод pack() непредсказуем – просто очевидно, что иногда размещение виджетов в окне в одном столбце, где один виджет помещается поверх предыдущего, не обязательно согласуется с нашим изощренным чувством эстетики. . В этих случаях мы можем либо использовать pack() с некоторыми умными аргументами, либо использовать grid() – еще один метод ориентации виджетов внутри контейнеров.

Изменив строки 15 и 16 из предыдущего примера, мы можем немного улучшить наш интерфейс:

simple_label.pack(fill="x")
closing_button.pack(fill="x")

Вывод:

Ориентация виджета

Таким простым способом мы говорим методу pack() растянуть метку и кнопку полностью вдоль горизонтальной оси. Мы также можем изменить способ, которым pack() создает новые виджеты внутри окна. Например, используя следующий аргумент:

simple_label.pack(side="left")
closing_button.pack(side="left")

Вывод:

Упаковка виджетов

Мы можем упаковать виджеты в один ряд, начиная с левой стороны окна. Однако pack() – не единственный метод ориентации виджетов внутри их родительских виджетов. Метод, который дает лучшие результаты, – это, вероятно, метод grid(), который позволяет нам упорядочивать виджеты по строкам и столбцам. Взгляните на следующий пример.

import tkinter

root = tkinter.Tk()

simple_label = tkinter.Label(root, text="Easy, right?")
another_label = tkinter.Label(root, text="More text")
closing_button = tkinter.Button(root, text="Close window", command=root.destroy)
another_button = tkinter.Button(root, text="Do nothing")

simple_label.grid(column=0, row=0, sticky="ew")
another_label.grid(column=0, row=1, sticky="ew")
closing_button.grid(column=1, row=0, sticky="ew")
another_button.grid(column=1, row=1, sticky="ew")

root.mainloop()

Вывод:

Использование функции pack()

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

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

Привязанный аргумент, вероятно, не так очевиден. Используя эту опцию, мы можем прикрепить края наших виджетов к краям их соответствующих ячеек сетки – северного (вверху), южного (внизу), восточного (справа) и западного (слева). Мы делаем это, передавая простую строку, содержащую конфигурацию букв n, s, e и w.

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

Теперь, когда вы знаете два разных метода ориентации виджетов, имейте в виду, что никогда не следует смешивать grid() и pack() внутри одного контейнера.

Frames

Windows – не единственные виджеты, которые могут содержать другие виджеты. Чтобы сделать ваши сложные интерфейсы более понятными, обычно рекомендуется разделять виджеты на фреймы.

Давайте попробуем сделать это с помощью наших четырех простых виджетов:

import tkinter

root = tkinter.Tk()

frame_labels = tkinter.Frame(root, borderwidth="2", relief="ridge")
frame_buttons = tkinter.Frame(root, borderwidth="2", relief="ridge")

simple_label = tkinter.Label(frame_labels, text="Easy, right?")
another_label = tkinter.Label(frame_labels, text="More text")

closing_button = tkinter.Button(frame_buttons, text="Close window", command=root.destroy)
another_button = tkinter.Button(frame_buttons, text="Do nothing")

frame_labels.grid(column=0, row=0, sticky="ns")
frame_buttons.grid(column=1, row=0)

simple_label.grid(column=0, row=0, sticky="ew")
another_label.grid(column=0, row=1, sticky="ew")

closing_button.pack(fill="x")
another_button.pack(fill="x")

root.mainloop()

Вывод:

Виджет Frame

Давайте внимательно рассмотрим пример, показанный выше. В строках 5 и 6 мы определяем два новых виджета Frame. Очевидно, что в первом аргументе мы указываем на их родительский виджет, которым является корневое окно.

По умолчанию границы Frame невидимы, но, допустим, мы хотели бы видеть, где именно они расположены. Чтобы показать их границы, мы должны дать им определенную ширину (в нашем примере 2 пикселя) и стиль рельефа (своего рода трехмерный эффект), в котором будет отображаться граница. На выбор предлагается 5 различных стилей relief – в нашем примере мы используем ridge.

Определения Label и Button также были немного изменены (строки 8-12). Мы хотели разместить наши метки в нашем фрейме frame_labels, а наши кнопки – в фрейме frame_buttons. Таким образом, нам пришлось заменить их предыдущий родительский элемент, root, на их соответствующие новые родительские элементы фрейма.

В строках 14 и 15 мы ориентируем фреймы внутри корневого окна с помощью метода grid(). Затем мы используем метод grid() для ориентации меток (строки 17–18) и метод pack() для ориентации кнопок (строки 20–21). Метки и кнопки теперь находятся в отдельных контейнерах, поэтому ничто не мешает нам ориентировать виджеты разными методами.

Окна верхнего уровня

Ваш интерфейс не должен содержать более одного корневого окна, но вы можете создать множество окон, которые являются дочерними по отношению к корневому окну. Лучший способ сделать это – использовать класс Toplevel.

import tkinter

root = tkinter.Tk()

new_window = tkinter.Toplevel()
new_window.withdraw()

frame_labels = tkinter.Frame(root, borderwidth="2", relief="ridge")
frame_buttons = tkinter.Frame(root, borderwidth="2", relief="ridge")

simple_label = tkinter.Label(frame_labels, text="Easy, right?")
another_label = tkinter.Label(frame_labels, text="More text")

closing_button = tkinter.Button(frame_buttons, text="Close window", command=root.destroy)
window_button = tkinter.Button(frame_buttons, text="Show new window", command=new_window.deiconify)

frame_labels.grid(column=0, row=0, sticky="ns")
frame_buttons.grid(column=1, row=0)

simple_label.grid(column=0, row=0, sticky="ew")
another_label.grid(column=0, row=1, sticky="ew")

closing_button.pack(fill="x")
window_button.pack(fill="x")

root.mainloop()

В приведенном выше примере мы создаем наше новое окно в строке 5. Поскольку окно – это объект, который не привязан к какому-либо другому виджету, нам не нужно указывать на его родительский элемент или ориентировать его внутри родительского виджета.

Мы хотели бы показывать новое окно после нажатия кнопки. В строке 5 он отображается сразу, поэтому мы используем метод remove() в строке 6, чтобы скрыть его. Затем мы изменяем определение кнопки в строке 15.

Помимо нового имени переменной и текста, кнопка теперь выполняет команду – метод объекта new_window, deiconify, который заставит окно снова появиться после того, как пользователь щелкнет кнопку window_button.

Заключение

Как видите, с помощью Tkinter вы можете легко и быстро создавать графические интерфейсы для непрофессиональных пользователей вашего программного обеспечения. Библиотека включена во все установки Python, поэтому создание вашего первого простого окна – это всего лишь пара строк кода.

Оставить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

This div height required for enabling the sticky sidebar