Замена виджетов и Combobox / tkinter 21

Скачайте код уроков с 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:

python –mtkinter

Замена классов базовых виджетов

В качестве первого пункта знакомства с тематическими виджетами 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:

Вы могли заметить, что для замены виджетов из модуля 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 выводится в стандартный вывод:

Создание выпадающего списка с 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() с пустой строкой:

С помощью этих методов вы знаете, как взаимодействовать с выбранным значением в экземпляре Combobox.

Класс ttk.Combobox расширяет ttk.Entry, который, в свою очередь, расширяет класс Entry из модуля tkinter.


Это значит, что можно использовать уже рассмотренные методы из класса Entry, если потребуется:


combobox.insert(0, "Добавьте это в начало: ")

Вот этот код более понятен чем combobox.set("Добавьте это в начало: " + combobox.get()).

Максим
Я создал этот блог в 2018 году, чтобы распространять полезные учебные материалы, документации и уроки на русском. На сайте опубликовано множество статей по основам python и библиотекам, уроков для начинающих и примеров написания программ.
Мои контакты: Почта
admin@pythonru.comAlex Zabrodin2018-10-26OnlinePython, Programming, HTML, CSS, JavaScript