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

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

14 ноября 2022 г.

Введение

Возможно, вы только начали изучать Python и создали одно или два простых приложения. Поздравляем! Но что теперь? А как насчет создания графического пользовательского интерфейса ("GUI") для взаимодействия с вашим блестящим новым приложением Python?

Существует несколько вариантов создания приложений с графическим интерфейсом с помощью Python, включая PyQt и < href="https://www.wxpython.org/">wxPython. Однако это руководство познакомит вас с Tkinter.

Tkinter, что означает «интерфейс Tk», является стандартом Python для создания графических интерфейсов и включено в Стандартная библиотека Python. Это привязка к Tk GUI toolkit, бесплатной библиотеке графических виджетов с открытым исходным кодом, которую можно использовать для создания графических интерфейсов на различных языках программирования.< /p>

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

Предпосылки

Для выполнения этого руководства вам потребуется:

* Установлен Python. * Установлен pip. * Установлена ​​библиотека часовых поясов pytz. Библиотеку можно установить с помощью pip.

pip install pytz

:::подсказка В этом руководстве термины корневое окно и главное окно используются взаимозаменяемо.

:::

Шаг 1. Создайте новое приложение Python и задайте необходимые параметры импорта

Создайте новое приложение Python с именем timezone.py и добавьте следующие операторы import для импорта Tkinter, datetime и модули pytz.

import tkinter as tk
import datetime
import pytz

Шаг 2. Добавьте часовые пояса

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

print(pytz.all_timezones)

Набор часовых поясов США, доступных через pytz, указывается в виде списка.

import tkinter as tk
import datetime
import pytz

timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"]

Шаг 3. Создание экземпляра класса Tk

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

import tkinter as tk
import datetime
import pytz

timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"]

root = tk.Tk()

Шаг 4. Настройка главного окна

На этом шаге настраивается корневое окно, в частности его заголовок, геометрия и возможность изменения размера.

Шаг 4а. Установка заголовка главного окна

Заголовок окна задается с помощью метода title.

import tkinter as tk
import datetime
import pytz

timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"]

root = tk.Tk()
root.title("Simple Timezone Application")

Шаг 4б. Настройка ширины и высоты главного окна

Значения ширины и высоты окна, выраженные в пикселях, можно присвоить переменным, чтобы упростить код.

import tkinter as tk
import datetime
import pytz

timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"]

root = tk.Tk()
root.title("Simple Timezone Application")

window_width = 450
window_height = 175

Шаг 4в. Расчет центрального положения главного окна

Главное окно можно разместить в любом месте экрана, например в центре, в верхнем левом углу и т. д. Окно по центру обеспечивает приятный внешний вид, а центральное положение главного окна можно определить с помощью winfo_screenwidth() корневого окна и winfo_screenheight() вместе с простой математикой. Эти два метода возвращают ширину и высоту экрана, которые используются для вычисления соответствующих координат (x, y) для центрирования главного окна. Как и в случае с шириной и высотой окна, значения центрального положения также могут быть присвоены переменным, чтобы сделать код более читабельным.

import tkinter as tk
import datetime
import pytz

timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"]

root = tk.Tk()
root.title("Simple Timezone Application")
window_width = 450
window_height = 175
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
center_x = int((screen_width - window_width)/2)
center_y = int((screen_height - window_height)/2)

Обратите внимание, что значения center_x и center_y также выражаются в пикселях, а int используется для обеспечения того, чтобы оба рассчитанных значения были целыми числами.

Шаг 4d. Настройка геометрии главного окна

Геометрия корневого окна, определяющая размер и положение главного окна, задается с помощью метода geometry корневого окна. Чтобы упростить задачу, вы можете использовать форматированный строковый литерал или f-строку, который будет интерполировать выражения переменных геометрии во время выполнения. В следующем блоке кода литерал f-string передается методу geometry в качестве параметра.

import tkinter as tk
import datetime
import pytz

timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"]

root = tk.Tk()
root.title("Simple Timezone Application")
window_width = 450
window_height = 175
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
center_x = int((screen_width - window_width)/2)
center_y = int((screen_height - window_height)/2)
root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}")

Шаг 4e. Настройка изменения размера главного окна

Возможность изменения размера корневого окна по осям x и y может быть установлена ​​с помощью метода resizable корневого окна. Метод resizable принимает параметры height и width в указанном порядке. True или ненулевое значение для любого из параметров указывает, что размер главного окна может изменяться вдоль соответствующей оси. Значение False или 0 для любого из параметров указывает, что размер главного окна не может изменяться вдоль заданной оси. Приложение таймера будет использовать значение False для высоты и ширины, чтобы предотвратить изменение размера главного окна.

import tkinter as tk
import datetime
import pytz

timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"]

root = tk.Tk()
root.title("Simple Timezone Application")
window_width = 450
window_height = 175
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
center_x = int((screen_width - window_width)/2)
center_y = int((screen_height - window_height)/2)
root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}")
root.resizable(False, False)

Шаг 5. Укажите сетку для макета виджета

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

  1. Упаковано с помощью метода pack(). Диспетчер геометрии pack() организует виджеты в блоки перед их добавлением в корневое окно или родительский виджет. Несовершенный, но, возможно, полезный способ подумать о упаковке — подумать о добавлении продуктов в сумку для продуктов. Элементы не обязательно добавляются в заранее определенные места в сумке. Скорее, они упаковываются один за другим, используя доступное пространство до тех пор, пока все предметы не будут помещены в сумку. Менеджер геометрии pack() работает аналогичным образом.
  2. Размещено с помощью метода place(). Диспетчер геометрии place() помещает виджеты в определенные заранее определенные позиции в корневом окне или родительском виджете. Этот менеджер геометрии, безусловно, полезен при создании точных макетов графического интерфейса.
  3. Организован в виде сетки с использованием метода grid(). Сетки — это двумерные таблицы строк/столбцов. Виджеты добавляются в сетку путем указания конкретной строки и столбца, в которые следует поместить виджет. Сетки настраиваются с помощью методов columnconfigure и rowconfigure корневого окна. Каждый из этих методов имеет атрибуты index и weight. Атрибут index указывает положение столбца или строки с использованием начального значения 0. Атрибут weight указывает размер определенного столбца или строки относительно других столбцов. Например, если столбец 0 имеет вес 1, а столбец 1 имеет вес 3, тогда столбец 1 будет в 3 раза больше, чем столбец 0.

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

import tkinter as tk
import datetime
import pytz

timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"]

root = tk.Tk()
root.title("Simple Timezone Application")
window_width = 450
window_height = 175
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
center_x = int((screen_width - window_width)/2)
center_y = int((screen_height - window_height)/2)
root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}")
root.resizable(False, False)

root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=1)
root.columnconfigure(2, weight=1)
root.columnconfigure(3, weight=1)

Шаг 6. Добавьте виджеты

На этом шаге виджеты добавляются в сетку главного окна, определенную на шаге 4. Приложение часового пояса будет использовать 3 виджета TKinter:

* Ярлык * Список * Кнопка

Виджеты Tkinter Label и Button точно такие, как они называются. Виджет Label позволяет программисту отображать текст (т.е. метку), а виджет Button используется для отображения кнопок. Виджет Listbox используется для выбора значения (или значений) из списка параметров.

Конечно, существуют и другие виджеты помимо трех, перечисленных выше, например виджеты SpinBox, Entry и Message. Официальная документация по командам Tk – это полезный ресурс для изучения подробнее о виджетах, доступных в наборе инструментов Tk.

Шаг 6а. Создание виджетов

Экземпляр каждого класса виджетов создается для данного виджета, используемого с дизайном графического интерфейса. Приложение часового пояса использует 4 экземпляра виджета: 2 виджета Label, 1 виджет Listbox и 1 виджет Button.

import tkinter as tk
import datetime
import pytz

timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"]

root = tk.Tk()
root.title("Simple Timezone Application")
window_width = 450
window_height = 175
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
center_x = int((screen_width - window_width)/2)
center_y = int((screen_height - window_height)/2)
root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}")
root.resizable(False, False)

root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=1)
root.columnconfigure(2, weight=1)
root.columnconfigure(3, weight=1)

# Instance of Label widget class for selection prompt.
select_timezone_label = tk.Label(root, text="Please select a timezone.")

# Instance of Listbox class for selection of timezone from list.
list_var = tk.Variable(value=timezones)
select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1)

# Instance of Button class to get the local time in the selected timezone.
select_timezone_button = tk.Button(root, text="Get Time")

# Second instance of the Label class to display the local time in the selected timezone.
time_label = tk.Label(root, text="")

Как видно из блока кода выше, каждый экземпляр виджета "привязан" к окну root. Виджет Listbox также требует создания экземпляра специального класса Tkinter Variable(), который используется для предоставления виджету списка параметров часового пояса, из которых пользователь может выбирать с помощью < code>Listbox Атрибут listvariable. Текст, отображаемый каждым виджетом Label, можно настроить с помощью атрибута text. Текстовое значение для time_label остается пустым, поскольку оно будет устанавливаться динамически каждый раз, когда пользователь «получает» время для выбранного часового пояса.

Шаг 6b. Размещение виджетов в сетке

Экземпляры виджетов, созданные на шаге 5а, можно поместить в сетку, определенную на шаге 4, с помощью метода grid(). Приложение часового пояса будет использовать следующие атрибуты метода grid() для определения макета:

* column: определяет конкретный столбец, в котором будет размещен виджет, используя основу 0. * row: определяет конкретную строку, в которой будет размещен виджет, используя основу 0. * columnspan: указывает, что виджет должен охватывать указанное количество столбцов. Например, виджет со значением columnspan=3 будет охватывать 3 столбца, даже если сам виджет меньше 3 столбцов. * sticky: Tkinter по умолчанию размещает виджет в центре ячейки по горизонтали и вертикали (т. е. в определенной позиции строки/столбца), где он размещен. Это поведение по умолчанию можно переопределить с помощью атрибута sticky, который использует значения, подобные компасу, включая NW, N, NE, W, E, SW, S и SE, чтобы выровнять виджет в определенном месте внутри ячейки виджета. Например, sticky=tK.W указывает, что виджет должен быть выровнен по западному углу своей ячейки сетки. Аналогично, sticky=tK.E указывает, что виджет должен быть выровнен по восточному углу своей ячейки сетки. * padx, pady: атрибуты padx и pady используются для добавления отступов по осям X и Y. соответственно со значениями, указанными в пикселях. Естественно, отступы могут обеспечить более профессиональный вид графического интерфейса, гарантируя, что виджеты не будут «ударять» непосредственно по краям корневого окна или других виджетов.

import tkinter as tk
import datetime
import pytz

timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"]

root = tk.Tk()
root.title("Simple Timezone Application")
window_width = 450
window_height = 175
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
center_x = int((screen_width - window_width)/2)
center_y = int((screen_height - window_height)/2)
root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}")
root.resizable(False, False)

root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=1)
root.columnconfigure(2, weight=1)
root.columnconfigure(3, weight=1)

# Instance of Label widget class for selection prompt.
select_timezone_label = tk.Label(root, text="Please select a timezone.")

# Instance of Listbox class for selection of timezone from list.
list_var = tk.Variable(value=timezones)
select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1)

# Instance of Button class to get the local time in the selected timezone.
select_timezone_button = tk.Button(root, text="Get Time")

# Second instance of the Label class to display the local time in the selected timezone.
time_label = tk.Label(root, text="")

# Place widgets on grid.
select_timezone_label.grid(column=0, row=0, columnspan=4, sticky=tk.W, padx=10, pady=10)
select_timezone_listbox.grid(column=0, row=1, columnspan=3, sticky=tk.EW, padx=10, pady=10)
select_timezone_button.grid(column=4, row=1, sticky=tk.E, padx=10, pady=10)
time_label.grid(column=0, row=4, columnspan=4, sticky=tk.W, padx=10, pady=10)

Шаг 7. Создание метода обратного вызова кнопки «Получить время»

Необходимо определить метод обратного вызова для обработки событий, когда пользователь нажимает кнопку select_timezone_button, созданную на шаге 5.

Шаг 7а. Привязка кнопки «Получить время»

Прежде чем определять логику обратного вызова, полезно сначала привязать кнопку к имени метода, который в конечном итоге будет содержать код обратного вызова. Метод bind() можно использовать в сочетании с функцией лямбда для привязки select_timezone_button к указанному методу обратного вызова. Также обратите внимание, что функция лямбда используется для передачи ссылок на виджеты select_timezone_listbox и time_label в качестве параметров обратного вызова. Эти параметры обратного вызова на самом деле не нужны, поскольку select_timezone_listbox и time_label находятся в глобальной области видимости. Тем не менее, возможно, полезно продемонстрировать, как аргументы могут быть переданы в функцию обратного вызова.

import tkinter as tk
import datetime
import pytz

timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"]

root = tk.Tk()
root.title("Simple Timezone Application")
window_width = 450
window_height = 175
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
center_x = int((screen_width - window_width)/2)
center_y = int((screen_height - window_height)/2)
root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}")
root.resizable(False, False)

root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=1)
root.columnconfigure(2, weight=1)
root.columnconfigure(3, weight=1)

# Instance of Label widget class for selection prompt.
select_timezone_label = tk.Label(root, text="Please select a timezone.")

# Instance of Listbox class for selection of timezone from list.
list_var = tk.Variable(value=timezones)
select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1)

# Instance of Button class to get the local time in the selected timezone.
select_timezone_button = tk.Button(root, text="Get Time")

# Second instance of the Label class to display the local time in the selected timezone.
time_label = tk.Label(root, text="")

# Place widgets on grid.
select_timezone_label.grid(column=0, row=0, columnspan=4, sticky=tk.W, padx=10, pady=10)
select_timezone_listbox.grid(column=0, row=1, columnspan=3, sticky=tk.EW, padx=10, pady=10)
select_timezone_button.grid(column=4, row=1, sticky=tk.E, padx=10, pady=10)
time_label.grid(column=0, row=4, columnspan=4, sticky=tk.W, padx=10, pady=10)

select_timezone_button.bind("<Button>", lambda e, args=[select_timezone_listbox, time_label]: get_timezone_time(e, args))

Шаг 7б. Определение логики обратного вызова

Логика обратного вызова для обработки событий нажатия кнопки определена ниже.

def get_timezone_time(e, args):
    select_timezone_listbox = args[0]
    time_label = args[1]
    selection_index = select_timezone_listbox.curselection()
    selected_timezone = select_timezone_listbox.get(selection_index)

    now_time = datetime.datetime.now()
    tz_time = now_time.astimezone(pytz.timezone(selected_timezone))
    tz_formatted = tz_time.strftime("%H:%M:%S")

    time_label.configure({"text": f"The time in {selected_timezone} is {tz_formatted}."})
    time_label.update()

Методы curselection() и get() используются для извлечения выбранного пользователем часового пояса из ссылки на виджет select_timezone_listbox. Затем текущее время пользователя преобразуется в выбранное время часового пояса. Наконец, метод configure используется для изменения атрибута text ссылки на time_label с указанием местного времени в выбранном часовом поясе. Обратите внимание, что метод update() используется, чтобы "заставить" виджет time_label обновлять себя новым текстовым значением.

Шаг 8. Завершите и запустите приложение

Метод mainloop() корневого окна применяется как последняя строка кода. Метод mainloop() будет запускать графический интерфейс в бесконечном цикле, пока пользователь не выйдет.

Завершенный код выглядит следующим образом:

import tkinter as tk
import datetime
import pytz

timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"]

def get_timezone_time(e, args):
    select_timezone_listbox = args[0]
    time_label = args[1]
    selection_index = select_timezone_listbox.curselection()
    selected_timezone = select_timezone_listbox.get(selection_index)

    now_time = datetime.datetime.now()
    tz_time = now_time.astimezone(pytz.timezone(selected_timezone))
    tz_formatted = tz_time.strftime("%H:%M:%S")

    time_label.configure({"text": f"The time in {selected_timezone} is {tz_formatted}."})
    time_label.update()

root = tk.Tk()
root.title("Simple Timezone Application")
window_width = 450
window_height = 175
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
center_x = int((screen_width - window_width)/2)
center_y = int((screen_height - window_height)/2)
root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}")
root.resizable(False, False)

root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=1)
root.columnconfigure(2, weight=1)
root.columnconfigure(3, weight=1)

# Instance of Label widget class for selection prompt.
select_timezone_label = tk.Label(root, text="Please select a timezone.")

# Instance of Listbox class for selection of timezone from list.
list_var = tk.Variable(value=timezones)
select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1)

# Instance of Button class to get the local time in the selected timezone.
select_timezone_button = tk.Button(root, text="Get Time")

# Second instance of the Label class to display the local time in the selected timezone.
time_label = tk.Label(root, text="")

# Place widgets on grid.
select_timezone_label.grid(column=0, row=0, columnspan=4, sticky=tk.W, padx=10, pady=10)
select_timezone_listbox.grid(column=0, row=1, columnspan=3, sticky=tk.EW, padx=10, pady=10)
select_timezone_button.grid(column=4, row=1, sticky=tk.E, padx=10, pady=10)
time_label.grid(column=0, row=4, columnspan=4, sticky=tk.W, padx=10, pady=10)

# Bind button to callback.
select_timezone_button.bind("<Button>", lambda e, args=[select_timezone_listbox, time_label]: get_timezone_time(e, args))

root.mainloop()

Когда приложение запущено, графический интерфейс должен выглядеть так:

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

Дальнейшие шаги

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

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

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


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE