Гид по технологиям

Создание GUI-календаря на Python с Tkinter

5 min read Python GUI Обновлено 05 Jan 2026
GUI-календарь на Python с Tkinter
GUI-календарь на Python с Tkinter

Зачем это полезно

Создание GUI-календаря — отличный учебный проект для тех, кто изучает разработку десктопных приложений на Python. Вы научитесь работать с виджетами Tkinter, управлять макетом, читать и форматировать даты через модуль calendar и datetime, а также добавлять пользовательские действия (показ, сброс, закрытие). Такой проект легко расширяется: напоминания, сохранение событий, синхронизация с внешними календарями.

Кратко о модулях (одно предложение каждое)

  • calendar — модуль стандартной библиотеки для операций с датами и форматирования календарей (текстовые/итерационные представления).
  • tkinter — стандартный GUI-фреймворк Python для сборки оконных приложений и виджетов.
  • datetime — модуль стандартной библиотеки для работы с датами и временем (классы date, datetime, timedelta).

Что делает базовый пример

  • Читает выбранный месяц и год из Spinbox.
  • С помощью calendar.month формирует текстовый календарь.
  • Показывает календарь в Text-виджете.
  • Есть кнопки: DISPLAY (показать), RESET (сбросить на текущий месяц/год), CLOSE (закрыть окно).

Исходный фрагмент функций (сохранён, как в оригинале)

from tkinter import *  
import calendar  
from datetime import date  
  
def printCalendar():  
    month = int(month_box.get())  
    year = int(year_box.get())  
    output_calendar = calendar.month(year, month)  
    calendar_field.delete(1.0, 'end')  
    calendar_field.insert('end', output_calendar)
def reset():  
    calendar_field.delete(1.0, 'end')  
    month_var.set(current_month)  
    year_var.set(current_year)  
    month_box.config(textvariable=month_var)  
    year_box.config(textvariable=year_var)
def close():  
    guiWindow.destroy()
if __name__ == "__main__":  
    guiWindow = Tk()  
    guiWindow.title("GUI Calendar")  
    guiWindow.geometry('500x550')  
    guiWindow.resizable(0, 0)  

(Далее в коде создаются фреймы, метки, Spinbox для месяца и года, Text-виджет и кнопки — все части показаны детально ниже.)

Человек записывает заметку в настольный календарь

Разбор ключевых виджетов и параметров

  • Tk(): создаёт корневое окно.
  • Frame: контейнер для логической группировки элементов.
  • Label: статический текст (заголовок, подписи).
  • Spinbox: удобный контрол для выбора числовых значений (месяц/год).
  • Text: многострочное текстовое поле — здесь мы отображаем текстовый календарь.
  • Button: кнопка с параметром command для привязки обработчика.

Важно: pack, grid и place — три основных менеджера компоновки Tkinter. В базовом примере используется place и pack; для адаптивных интерфейсов предпочтительнее использовать grid или комбинировать pack и grid осознанно.

Как собрать интерфейс — шаги

  1. Импортировать библиотеки.
  2. Создать окно и настроить его свойства (title, geometry, resizable).
  3. Создать фреймы и разместить их (pack/place/grid).
  4. Добавить метки, Spinbox, Text и кнопки.
  5. Реализовать обработчики: printCalendar, reset, close.
  6. Запустить главный цикл guiWindow.mainloop().

Важные фрагменты исходного кода (оригинальные блоки сохранены)

    header_frame = Frame(guiWindow)  
    entry_frame = Frame(guiWindow)  
    result_frame = Frame(guiWindow)  
    button_frame = Frame(guiWindow)  
  
    header_frame.pack(expand=True, fill="both")  
    entry_frame.pack(expand=True, fill="both")  
    result_frame.pack(expand=True, fill="both")  
    button_frame.pack(expand=True, fill="both")
    header_label = Label(header_frame, text="CALENDAR",  
       font=('arial', '45', 'bold'), fg="#A020F0")  
  
    header_label.pack(expand=True, fill="both")  
  
    month_label = Label(entry_frame, text="Month:",  
       font=("arial", "20", "bold"), fg="#000000")  
  
    year_label = Label(entry_frame, text="Year:",  
       font=("arial", "20", "bold"), fg="#000000")  
  
    month_label.place(x=30, y=0)  
    year_label.place(x=275, y=0)  
    month_var = IntVar(entry_frame)  
    year_var = IntVar(entry_frame)
    current_month = date.today().month  
    current_year = date.today().year  
    month_var.set(current_month)  
    year_var.set(current_year)  
  
    month_box = Spinbox(entry_frame, from_=1, to=12, width="10",  
       textvariable=month_var, font=('arial','15'))  
  
    year_box = Spinbox(entry_frame, from_=0000, to=3000, width="10",  
       textvariable=year_var,font=('arial','15'))  
  
    month_box.place(x=130, y=5)  
    year_box.place(x=360, y=5)
    calendar_field = Text(result_frame, width=20, height=8,  
       font=("courier", "18"), relief=RIDGE, borderwidth=2)  
  
    calendar_field.pack()  
  
    display_button = Button(button_frame, text="DISPLAY", bg="#A020F0",  
       fg="#E0FFFF", command=printCalendar, font=('arial', '15'))  
  
    reset_button = Button(button_frame, text="RESET", bg="#A020F0",  
       fg="#E0FFFF", command=reset, font=('arial','15'))  
  
    close_button = Button(button_frame, text="CLOSE", bg="#A020F0",  
       fg="#E0FFFF", command=close, font=('arial','15'))  
  
    display_button.place(x=55, y=0)  
    reset_button.place(x=210, y=0)  
    close_button.place(x=350, y=0)
    guiWindow.mainloop()

Пример вывода

При запуске приложения отображается окно с текущим месяцем и годом. Кнопка Reset возвращает значения на текущую дату.

Окно с календарём и текущим месяцем

При установке месяца 3 и года 2000 программа отобразит календарь за март 2000. Кнопка Close закроет окно и завершит выполнение.

Календарь марта 2000 года

Частые улучшения и расширения

  • Сохранение событий в локальную базу (JSON/SQLite).
  • Отправка напоминаний по расписанию (через планировщик задач или фоновые потоки).
  • Добавление цветовой маркировки для событий и праздников.
  • Переключение первого дня недели (понедельник/воскресенье) через calendar.TextCalendar(firstweekday=6).

Альтернативные подходы

  • Использовать tkinter.ttk для современных виджетов и тем.
  • Переехать на PyQt или PySide для более сложного интерфейса и богатых виджетов.
  • Для веб-доступа — реализовать календарь как веб-приложение (Flask/FastAPI + frontend).

Когда такое решение не подходит

  • Если требуется синхронизация с онлайн-календарями (Google Calendar, Outlook), лучше использовать API-ориентированную архитектуру с хранением событий на сервере.
  • Для мобильных приложений предпочтительнее нативные инструменты (iOS/Android) или кроссплатформенные фреймворки.

Мини-методология для расширения проекта (шаги)

  1. Добавьте модель события: id, дата, время, заголовок, описание, цвет.
  2. Выберите способ хранения: JSON для простого прототипа, SQLite для устойчивости.
  3. Нарисуйте UX: как пользователь создаёт/редактирует/удаляет событие.
  4. Реализуйте сохранение и загрузку при старте/закрытии приложения.
  5. Добавьте фоновый таймер для напоминаний или интеграцию с системными уведомлениями.

Роль‑ориентированные чек‑листы

  • Разработчик:
    • Кодируется базовый интерфейс и обработчики.
    • Добавлен unit-test на парсинг месяца/года и генерацию текста calendar.month.
    • Отдельный модуль для хранения данных.
  • Тестировщик:
    • Проверить диапазоны Spinbox (1–12 для месяцев, границы года).
    • Проверить корректность для високосного года (февраль).
    • Проверить закрытие окна и освобождение ресурсов.
  • Дизайнер:
    • Проверить читаемость шрифтов и контраст.
    • Предложить улучшения в расположении кнопок для UX.

Критерии приёмки

  • Приложение запускается без ошибок на Windows/macOS/Linux (с установленным Python и Tkinter).
  • Отображается текущий месяц при запуске.
  • Кнопка DISPLAY показывает выбранный месяц/год.
  • Кнопка RESET возвращает текущий месяц и год.
  • Кнопка CLOSE завершает приложение корректно.

Тестовые сценарии (короткие)

  • Значение месяца = 1..12: календарь соответствует ожиданию.
  • Значение года = 0 и 3000: приложение должно корректно отобразить календарь (если год в допустимом диапазоне calendar).
  • Ввод нечисловых символов в Spinbox: Spinbox по умолчанию принимает числовой ввод; проверить поведение и добавить валидацию при необходимости.
  • Високосный год (например, 2000): февраль должен показывать 29 дней.

Ментальная модель (как думать о задаче)

Подумайте о приложении как о трёх слоях: представление (Tkinter/виджеты), логика (формирование календаря и обработчики) и хранилище (будущие события). Упрощённая аналогия: виджеты — это GUI, calendar/datetime — библиотека для «текста календаря», а данные событий — ваша база.

Полный рабочий пример (собранный из частей выше — для запуска)

from tkinter import *
import calendar
from datetime import date

def printCalendar():
    try:
        month = int(month_box.get())
        year = int(year_box.get())
        output_calendar = calendar.month(year, month)
        calendar_field.delete(1.0, 'end')
        calendar_field.insert('end', output_calendar)
    except Exception as e:
        calendar_field.delete(1.0, 'end')
        calendar_field.insert('end', f"Ошибка: {e}")

def reset():
    calendar_field.delete(1.0, 'end')
    month_var.set(current_month)
    year_var.set(current_year)
    month_box.config(textvariable=month_var)
    year_box.config(textvariable=year_var)

def close():
    guiWindow.destroy()

if __name__ == "__main__":
    guiWindow = Tk()
    guiWindow.title("GUI Calendar")
    guiWindow.geometry('500x550')
    guiWindow.resizable(0, 0)

    header_frame = Frame(guiWindow)
    entry_frame = Frame(guiWindow)
    result_frame = Frame(guiWindow)
    button_frame = Frame(guiWindow)

    header_frame.pack(expand=True, fill="both")
    entry_frame.pack(expand=True, fill="both")
    result_frame.pack(expand=True, fill="both")
    button_frame.pack(expand=True, fill="both")

    header_label = Label(header_frame, text="CALENDAR",
       font=('arial', '45', 'bold'), fg="#A020F0")
    header_label.pack(expand=True, fill="both")

    month_label = Label(entry_frame, text="Month:",
       font=("arial", "20", "bold"), fg="#000000")
    year_label = Label(entry_frame, text="Year:",
       font=("arial", "20", "bold"), fg="#000000")

    month_label.place(x=30, y=0)
    year_label.place(x=275, y=0)

    month_var = IntVar(entry_frame)
    year_var = IntVar(entry_frame)

    current_month = date.today().month
    current_year = date.today().year
    month_var.set(current_month)
    year_var.set(current_year)

    month_box = Spinbox(entry_frame, from_=1, to=12, width="10",
       textvariable=month_var, font=('arial','15'))
    year_box = Spinbox(entry_frame, from_=0, to=3000, width="10",
       textvariable=year_var,font=('arial','15'))

    month_box.place(x=130, y=5)
    year_box.place(x=360, y=5)

    calendar_field = Text(result_frame, width=20, height=8,
       font=("courier", "18"), relief=RIDGE, borderwidth=2)
    calendar_field.pack()

    display_button = Button(button_frame, text="DISPLAY", bg="#A020F0",
       fg="#E0FFFF", command=printCalendar, font=('arial', '15'))
    reset_button = Button(button_frame, text="RESET", bg="#A020F0",
       fg="#E0FFFF", command=reset, font=('arial','15'))
    close_button = Button(button_frame, text="CLOSE", bg="#A020F0",
       fg="#E0FFFF", command=close, font=('arial','15'))

    display_button.place(x=55, y=0)
    reset_button.place(x=210, y=0)
    close_button.place(x=350, y=0)

    guiWindow.mainloop()

Советы по локализации и улучшению UX

  • Подумайте о переводе меток (Month/Year/DISPLAY/RESET/CLOSE) на целевой язык — в русскоязычной версии лучше заменить на “Месяц”, “Год”, “Показать”, “Сброс”, “Закрыть”.
  • Формат даты отображения можно локализовать в соответствии с региональными настройками; для этого используйте babel или вручную форматируйте строки.
  • Для экранов с разными DPI тестируйте масштабирование шрифтов и размеры виджетов.

Безопасность и производительность (коротко)

  • Для простого календаря особых уязвимостей нет, но если вы добавляете импорт/парсинг внешних файлов — валидируйте ввод.
  • Для большого количества событий используйте SQLite вместо хранения в оперативной памяти.

Примеры проектов для практики

  • Тайпинг‑тест с измерением WPM и сохранением результатов.
  • Палитра цветов с возможностью копирования HEX/RGB.
  • Конвертер валют с запросом к публичному API.
  • Калькулятор с историей вычислений.

Ключевые идеи на выходе

  • Tkinter хорошо подходит для простых десктопных приложений и прототипов.
  • Модуль calendar удобен для быстрого текстового представления месяца.
  • Архитектура: интерфейс — логика — хранилище; планируйте расширение заранее.

Примечание: если вы хотите подключить синхронизацию с внешними календарями (Google, Microsoft), изучите соответствующие API и авторизацию OAuth.

Короткий словарь (1 строка на термин)

  • Spinbox — виджет для выбора числового значения с кнопками увеличения/уменьшения.
  • Text — многострочный текстовый виджет.
  • Frame — контейнер для компоновки элементов интерфейса.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Сменить имя пользователя и отображаемое имя в Bluesky
Социальные сети

Сменить имя пользователя и отображаемое имя в Bluesky

Настройка HiDPI в Linux — руководство
Linux

Настройка HiDPI в Linux — руководство

Панель клавиатурных сочетаний Windows
Windows

Панель клавиатурных сочетаний Windows

Как связать Shazam со Spotify и слушать треки
Музыка

Как связать Shazam со Spotify и слушать треки

Исправить ошибку Microsoft Store 0x00000000
Windows

Исправить ошибку Microsoft Store 0x00000000

Пользовательские блоки в Google Документах
Google Документы

Пользовательские блоки в Google Документах