Скачайте код уроков с GitLab: https://gitlab.com/PythonRu/tkinter-uroki
Тематические виджеты Tk — это отдельная коллекция виджетов Tk, которые выглядят и ощущаются как нативные, и могут быть кастомизированы с помощью API.
Эти классы определены в модуле tkinter.ttk
. Помимо новых виджетов, таких как Treeview и Notebook, этот модуль предлагает альтернативную реализацию классических виджетов Tk: Button, Label и Frame.
В этом материале рассмотрим, как использовать эти классы, как их стилизовать и как применять новые классы виджетов.
Набор тематических виджетов Tk был представлен в Tk 8.5, что не должно быть проблемой, ведь установка Python как минимум версии 3.6 добавляет интерпретатор Tcl/Tk версии 8.6.
Убедиться в этом можно, набрав на любой платформе в командной строке python –mtkinter
. После этого запустится следующая программа с указанием текущей версии Tcl/Tk:
Замена классов базовых виджетов
В качестве первого пункта знакомства с тематическими виджетами Tkinter посмотрим, как использовать уже знакомые (Button, Label, Entry и так далее), но взятые из другого модуля, сохраняя то же поведение в приложении.
Хотя это не даст аналогичных возможностей в плане настройки стилей, достаточно обратить внимание на визуальные отличия, которые привносят нативные дизайн и «ощущения» этих тематических виджетов.
На следующем скриншоте можно увидеть различия между тематическим виджетом и стандартным виджетом Tkinter:
Создадим приложение с первого скриншота, но рассмотрим, как легко переключаться между разными стилями.
Стоит отметить, что это поведение сильно зависит от платформы. В этом конкретном случае тематический виджет повторяет внешний вид виджетов с Windows 10.
Чтобы начать использовать тематические виджеты нужны импортировать модуль tkinter.ttk
и привычным образом использовать виджеты из него в приложении:
import tkinter as tk
import tkinter as ttk
class App(tk.Tk):
greetings = ("Привет", "Ciao", "Hola")
def __init__(self):
super().__init__()
self.title("Тематические виджеты Tk")
var = tk.StringVar()
var.set(self.greetings[0])
label_frame = ttk.LabelFrame(self, text="Выберите приветствие")
for greeting in self.greetings:
radio = ttk.Radiobutton(label_frame, text=greeting,
variable=var, value=greeting)
radio.pack()
frame = ttk.Frame(self)
label = ttk.Label(frame, text="Введите ваше имя")
entry = ttk.Entry(frame)
command = lambda: print("{}, {}!".format(var.get(), entry.get()))
button = ttk.Button(frame, text="Приветствовать", command=command)
label.grid(row=0, column=0, padx=5, pady=5)
entry.grid(row=0, column=1, padx=5, pady=5)
button.grid(row=1, column=0, columnspan=2, pady=5)
label_frame.pack(side=tk.LEFT, padx=10, pady=10)
frame.pack(side=tk.LEFT, padx=10, pady=10)
if __name__ == "__main__":
app = App()
app.mainloop()
Если же в будущем потребуется переключиться к обычным виджетам Tkinter, то достаточно заменить все ttk.
на tk.
.
Как работает замена виджетов
Чтобы начать использовать тематически виджеты нужно импортировать модуль tkinter.ttk
с помощь синтаксиса import … as
. Это позволит быстро отличать стандартные виджеты благодаря имени tk
и тематические — с именем ttk
:
import tkinter as tk
import tkinter as ttk
Вы могли заметить, что для замены виджетов из модуля tkinter
на аналогичные им из tkinter.ttk
достаточно просто поменять алиас:
import tkinter as tk
import tkinter as ttk
# ...
entry_1 = tk.Entry(root)
entry_2 = ttk.Entry(root)
В этом примере мы делаем это с помощью виджетов ttk.Frame
, ttk.Label
, ttk.Entry
, ttk.LabelFrame
и ttk.Radiobutton
. Эти классы принимают почти те же базовые параметры, что и эквиваленты из Tkinter. На самом деле, они являются их подклассами.
Тем не менее эта смена довольно простая, потому что в этом случае не переносятся никакие особенности стиля: например, foreground
и background
. В тематических виджетах эти ключевые слова используются в классе ttk.Style
, речь о котором пойдет дальше.
Создание редактируемого выпадающего списка с Combobox
Выпадающие списки — это удобный способ выбора значения с помощью отображения вертикального списка значений только тогда, когда они нужны. Традиционно пользователям также позволяют добавить свой вариант, которого нет в списке.
Эта функциональность комбинируется с классом ttk.Combobox
, который выглядит и ощущается как нативные (для конкретной платформы) выпадающие списки.
Следующее приложение будет состоять из простого выпадающего списка с парой кнопок для подтверждения или сброса содержимого.
Если одно из имеющихся значений выбирается и нажимается кнопка Submit, то текущее значение Combobox выводится в стандартный вывод:
Это приложение создает экземпляр ttk.Combobox
при инициализации, передавая заранее определенную последовательность значений, которые можно будет выбирать из списка:
import tkinter as tk
import tkinter.ttk as ttk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("Ttk Combobox")
colors = ("Purple", "Yellow", "Red", "Blue")
self.label = ttk.Label(self, text="Пожалуйста, выберите цвет")
self.combo = ttk.Combobox(self, values=colors)
btn_submit = ttk.Button(self, text="Разместить",
command=self.display_color)
btn_clear = ttk.Button(self, text="Очистить",
command=self.clear_color)
self.combo.bind("<>", self.display_color)
self.label.pack(pady=10)
self.combo.pack(side=tk.LEFT, padx=10, pady=5)
btn_submit.pack(side=tk.TOP, padx=10, pady=5)
btn_clear.pack(padx=10, pady=5)
def display_color(self, *args):
color = self.combo.get()
print("Ваш выбор", color)
def clear_color(self):
self.combo.set("")
if __name__ == "__main__":
app = App()
app.mainloop()
Как работает виджет Combobox
Традиционно виджет ttk.Combobox
добавляется в приложение через передачу экземпляра Tk
в качестве первого параметра в конструктор. Параметр values
определяет список выбираемых вариантов, которые будут отображаться по клику.
Также выполняется связывание виртуального события <<ComboboxSelected>>
при выборе одного из значений списка:
self.label = ttk.Label(self, text="Пожалуйста, выберите цвет")
self.combo = ttk.Combobox(self, values=colors)
btn_submit = ttk.Button(self, text="Разместить",
command=self.display_color)
btn_clear = ttk.Button(self, text="Очистить",
command=self.clear_color)
self.combo.bind("<<ComboboxSelected>>", self.display_color)
Тот же метод вызывается при клике по кнопке Submit
, так что она получает значение, введенное пользователем.
display_color()
принимает переменный список аргументов с помощью синтаксиса *, что позволяет безопасно обрабатывать опциональные аргументы. Это происходит, потому что событие передается внутрь при вызове через связывание. Однако функция не получает параметры при вызове через колбек кнопки.
Внутри этого метода мы получаем текущее значение Combobox с помощью метода get()
и выводим его:
def display_color(self, *args):
color = self.combo.get()
print("Ваш выбор", color)
Наконец, clear_color()
очищает содержимое Combobox с помощью вызова set()
с пустой строкой:
def clear_color(self):
self.combo.set("")
С помощью этих методов вы знаете, как взаимодействовать с выбранным значением в экземпляре Combobox.
Класс ttk.Combobox
расширяет ttk.Entry
, который, в свою очередь, расширяет класс Entry
из модуля tkinter
.
Это значит, что можно использовать уже рассмотренные методы из класса Entry
, если потребуется:
combobox.insert(0, "Добавьте это в начало: ")
Вот этот код более понятен чем combobox.set("Добавьте это в начало: " + combobox.get())
.