Tkinter. 5 типов кнопок и пример структуры приложения

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

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

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

Тем не менее, если программа сложная, появляется необходимость дополнительно структурировать ее. Ведь даже несмотря на то, что требуется немного строк кода, со временем их будет достаточно много. Естественно, от этого страдает его читаемость.

Что такое Tkinter?

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

  1. Создавать окна, которые будут выполняться на разных системах (не забываем о том, что Python – кроссплатформенный язык программирования).
  2. Добавлять надписи на окна.
  3. Создавать всплывающие сообщения. 
  4. Задавать размеры и тип шрифта. Также поддерживается изменение цвета текста и всех элементов окна. 
  5. Осуществлять настройку размеров окна программ. 
  6. Управлять событиями при нажатии на кнопку.
  7. Вводить пользовательские данные с помощью полей ввода разного уровня. В том числе, можно задавать фокус полей ввода, чтобы пользователь сразу мог вводить, не нажимая предварительно по соответствующему элементу.
  8. Осуществлять добавление всплывающих списков.
  9. Добавлять радиокнопки (последовательностей кнопок, где одна из них может быть только нажата в определенный момент времени), с помощью которых можно выбирать один элемент из нескольких.
  10. Добавлять чекбоксы – места под галочки, когда пользователь может выбрать несколько объектов из определенного набора (например, если есть список цветов, и нужно выбрать 5 тех, которые больше всего нравятся).

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

Пример

Итак, давайте попробуем взять такое приложение.

from tkinter import *

root = Tk()

btn = Button(root, text=»Нажми!»)

btn.config(command=lambda: print(«Привет, Tkinter!»))

btn.pack(padx=120, pady=30)

root.title(«Мое приложение Tkinter»)

root.mainloop()

Работает она следующим образом. Создается окно, в котором расположена кнопка «Нажми». Если человек делает клик по ней, выводится надпись «Привет, Tkinter». Сама кнопка имеет координаты 120px по горизонтали и 30px – по вертикали. И, наконец, последняя строка нужна для того, чтобы приложение не закрылось до тех пор, пока не будет нажата соответствующая кнопка. То есть, это цикл, который обновляет интерфейс.

Сама программа выглядит так.Tkinter. 5 типов кнопок и пример структуры приложения

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

При этом не рекомендуется использовать Wildcard-импорты типа from … import *, поскольку они еще больше засоряют его. В нашем примере они используются для того, чтобы продемонстрировать, как не стоит делать.

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

Как правильно?

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

import tkinter as tk

class App(tk.Tk):

    def __init__(self):

        super().__init__()

        self.btn = tk.Button(self, text=»Нажми!»,

                             command=self.say_hello)

        self.btn.pack(padx=120, pady=30)

    def say_hello(self):

        print(«Привет, Tkinter!»)

if __name__ == «__main__»:

    app = App()

    app.title(«Мое приложение Tkinter»)

    app.mainloop()

Обратите внимание, что каждая переменная хранится в конкретной области видимости. Причем исключений нет и для функции command, расположенной внутри отдельного метода.

Принцип работы программы

В первую очередь надо использовать конструкцию import … as вместо wildcard-импорта. Это позволяет более оперативно получать информацию из глобального пространства имен. 

После этого класс App определяем в виде подкласса Tk, который в нашем примере ссылается на одноименное пространство имен. Мы используем метод __init__(), относящийся к объявленному нами ранее классу с использованием функции super()

Так создается ссылка на элемент класса App с переменной self. Поэтому виджет кнопки в этом примере добавляется не как самостоятельный элемент, а как атрибут класса.

Здесь у вас может появиться закономерный вопрос: зачем все так усложнять? На деле же, это поможет упростить взаимодействие с кодом в будущем. Лучше напрячься один раз, а потом не мучиться, перечитывая код миллиард раз и допуская ошибки одну за одной. 

Благодаря этому подходу программист получает возможность работать по отдельности с каждой частью. Кнопка отделена от ее нажатия, а генерация размещена в блоке if __name__ == «main». А вот это – типичная практика для кода в Python.

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

Дополнение о структуре приложения

В описанном выше примере кода мы отнести класс Tk в отдельный. Тем не менее, очень часто выделяются и другие классы виджетов. Это делается для того, чтобы была возможность воссоздавать те инструкции, которые были до рефакторинга.

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

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

Работа с виджетами-кнопками

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

Создание кнопки

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

Приведем теперь пример кода, который реализует эту задумку.

import tkinter as tk

RELIEFS = [tk.SUNKEN, tk.RAISED, tk.GROOVE, tk.RIDGE, tk.FLAT]

class ButtonsApp(tk.Tk):

    def __init__(self):

        super().__init__()

        self.img = tk.PhotoImage(file=»python.gif»)

        self.btn = tk.Button(self, text=»Кнопка с изображением»,

                             image=self.img, compound=tk.LEFT,

                             command=self.disable_btn)

        self.btns = [self.create_btn(r) for r in RELIEFS]

        self.btn.pack()

        for btn in self.btns:

            btn.pack(padx=10, pady=10, side=tk.LEFT)

    def create_btn(self, relief):

        return tk.Button(self, text=relief, relief=relief)

    def disable_btn(self):

        self.btn.config(state=tk.DISABLED)

if __name__ == «__main__»:

    app = ButtonsApp()

    app.mainloop()

Самый легкий метод генерации кнопки – это использовать параметр text, чтобы настроить надпись на ней, а также command, который используется с целью задания события клика.

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

Теперь рассмотрим второй ряд кнопок в этой программе. Чтобы его создать, используется список и перечень значений RELIEF. По надписи на каждой кнопке мы можем увидеть, что делает та или иная константа. 

Хотя вне метода __init__ атрибута нет, он использовался для сохранения ссылки на экземпляр изображения. Это нужно делать, чтобы при сборке мусора изображение не было удалено. Если бы мы объявляли изображения в качестве локальных переменных, то такая неприятная ситуация обязательно бы возникла. Поэтому надо всегда, пока окно, где есть кнопка с картинкой, не закрыто, помнить о том, что надо сохранять ссылку на этот объект. Иначе она просто пропадет.

ОфисГуру
Adblock
detector