Разработка многостраничных веб-приложений на Flet

Практический курс для Python-разработчиков по созданию кроссплатформенных интерфейсов без использования HTML и CSS [ixbt.com](https://www.ixbt.com/live/sw/gayd-po-flet-pristua.html). Вы научитесь верстать макеты, работать с событиями и реализуете полноценную навигацию для многостраничных сайтов [habr.com](https://habr.com/ru/companies/amvera/articles/858292).

1. Введение в Flet: установка, настройка окружения и структура приложения

Введение в Flet: установка, настройка окружения и структура приложения

Flet — это фреймворк, который позволяет создавать интерактивные многопользовательские веб-приложения, десктопные и мобильные приложения, используя только язык Python. Главная особенность Flet заключается в том, что он избавляет разработчика от необходимости писать frontend-код на HTML, CSS и JavaScript. Вместо этого вы оперируете объектами Python, а Flet транслирует их в визуальные компоненты на базе Flutter (UI-toolkit от Google).

Для Python-разработчика со знанием объектно-ориентированного программирования (ООП) переход на Flet будет интуитивным: интерфейс строится как дерево объектов, где каждый элемент (кнопка, текст, контейнер) является экземпляром класса.

Установка и настройка окружения

Для работы с Flet требуется Python версии 3.7 или выше. Рекомендуется использовать виртуальное окружение для изоляции зависимостей проекта.

Создание виртуального окружения

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

Для Windows:

Для macOS/Linux:

Установка библиотеки

После активации виртуального окружения установите Flet с помощью менеджера пакетов pip:

Эта команда установит все необходимые зависимости, включая встроенный веб-сервер для локальной разработки.

Базовая структура приложения

Минимальное приложение на Flet состоит из трех основных частей:

  • Импорт библиотеки.
  • Функция main, которая является точкой входа и принимает объект страницы.
  • Запуск приложения через ft.app.
  • Рассмотрим код простейшего приложения:

    Разбор компонентов

    * import flet as ft: Общепринятый стандарт импорта. Все классы и функции библиотеки будут доступны через префикс ft. * ft.Page: Это холст вашего приложения. Объект page представляет собой окно браузера (в веб-версии) или окно программы (в десктоп-версии). Он хранит состояние интерфейса и список отображаемых элементов. * ft.Text: Это контрол (виджет). В Flet все элементы интерфейса называются контролами. Это классы, которые имеют свойства (цвет, размер, текст) и методы. * page.add(): Метод, который помещает контрол в список отображения страницы. Важно понимать, что создание объекта ft.Text не отображает его автоматически — его нужно явно добавить на страницу. * ft.app(target=main): Запускает цикл событий приложения. Аргумент target указывает на функцию, которая будет выполнена при старте.

    !Слева блок Python Code с объектами Page и Controls. Стрелка ведет к блоку Flet Server. От него стрелки ведут к трем блокам: Web Browser, Desktop Window, Mobile Screen. Схема показывает, как один код превращается в интерфейс на разных платформах

    Дерево контролов и компоновка

    Поскольку вы не используете HTML, структура страницы определяется вложенностью объектов Python. Чтобы расположить элементы не просто друг под другом, а в определенном порядке, используются контейнеры компоновки: Row (строка) и Column (колонка).

    Row и Column

    * Column: Выстраивает дочерние элементы вертикально (сверху вниз). * Row: Выстраивает дочерние элементы горизонтально (слева направо).

    Пример использования:

    Свойство controls принимает список list объектов, которые должны находиться внутри контейнера. Это похоже на вложенность тегов <div> в HTML, но реализовано через списки Python.

    Интерактивность и обновление состояния

    Одна из самых частых ошибок новичков в Flet — забыть обновить страницу или контрол после изменения данных. Flet не отслеживает изменения переменных Python автоматически. Вы должны явно сообщить фреймворку, что состояние изменилось.

    Для этого используется метод .update().

    Пример счетчика нажатий

    Рассмотрим пример, где мы используем ООП подход и обработку событий.

    В этом примере:

  • Мы создали функции minus_click и plus_click. Они принимают аргумент e (событие), который содержит информацию о клике.
  • Мы привязали эти функции к кнопкам через свойство on_click.
  • Внутри функций мы меняем значение value текстового поля.
  • Мы вызываем txt_number.update(), чтобы перерисовать только текстовое поле с новым значением.
  • > Вызов page.update() перерисовывает всю страницу целиком. Для производительности лучше вызывать .update() у конкретных измененных контролов, когда это возможно.

    Запуск в режиме веб-приложения

    По умолчанию ft.app(target=main) запускает приложение в нативном окне операционной системы. Чтобы увидеть, как оно будет выглядеть в браузере (как веб-сайт), нужно изменить параметры запуска:

    При запуске скрипта Flet поднимет локальный веб-сервер и автоматически откроет ваш браузер по умолчанию.

    Итоги

    * Flet позволяет писать интерфейсы на чистом Python, используя дерево объектов (контролов). * Основной структурной единицей является ft.Page, на которую добавляются контролы с помощью метода page.add(). * Для компоновки элементов используются контейнеры Row (строка) и Column (колонка). * Изменения в свойствах объектов не отображаются мгновенно; необходимо вызывать метод .update() для перерисовки элемента или страницы. * Приложение может быть запущено как десктопная программа или как веб-сайт путем изменения параметра view в функции ft.app.

    2. Основы верстки: работа с контейнерами, рядами и колонками

    Основы верстки: работа с контейнерами, рядами и колонками

    В предыдущей статье мы научились создавать простейшее приложение и выводить текст. Однако реальные интерфейсы требуют сложной структуры: кнопки должны стоять рядом с полями ввода, боковая панель должна занимать всю высоту экрана, а карточки товаров — выстраиваться в сетку.

    В Flet, как и во Flutter, верстка строится на принципе вложенности. Здесь нет CSS-селекторов. Позиционирование элемента определяется тем, в какой родительский контрол он вложен и какие параметры этому родителю заданы.

    Оси выравнивания: MainAxis и CrossAxis

    Прежде чем углубляться в код, необходимо понять геометрию Flet. У контейнеров компоновки (Row и Column) есть две оси:

  • Main Axis (Главная ось): Направление, вдоль которого выстраиваются элементы.
  • * Для Row (ряд) — это горизонталь. * Для Column (колонка) — это вертикаль.
  • Cross Axis (Поперечная ось): Направление, перпендикулярное главной оси.
  • * Для Row — это вертикаль. * Для Column — это горизонталь.

    !Направление главной и поперечной осей в Row и Column

    Управление этими осями осуществляется через свойства alignment (для главной оси) и cross_alignment (для поперечной).

    Выравнивание в Row (Ряд)

    Допустим, мы хотим разместить три кнопки в ряд.

    Основные значения MainAxisAlignment: * START: Элементы прижаты к началу (слева для Row). * END: Элементы прижаты к концу (справа для Row). * CENTER: Элементы по центру. * SPACE_BETWEEN: Крайние элементы прижаты к границам, свободное место распределено между ними. * SPACE_EVENLY: Свободное место распределено равномерно перед первым, между элементами и после последнего.

    Выравнивание в Column (Колонка)

    Логика та же, но оси меняются местами.

    > Обратите внимание: у Row свойство поперечной оси называется vertical_alignment, а у Columnhorizontal_alignment. Это сделано для ясности, хотя суть одна — CrossAxisAlignment.

    Container: Декор и отступы

    Контролы Row и Column не имеют визуального отображения (цвета, границ), они отвечают только за позицию. Если вам нужно создать видимый блок, добавить фон, рамку или отступы, используется Container.

    ft.Container — это аналог тега <div> в HTML с CSS-стилями. Он может содержать в себе только один дочерний элемент (свойство content). Если нужно положить в контейнер много элементов, сначала оберните их в Column или Row, а затем поместите эту группу в content контейнера.

    Padding и Margin

    Два ключевых свойства для создания "воздуха" в интерфейсе:

  • Padding (Внутренний отступ): Расстояние от границы контейнера до его содержимого.
  • Margin (Внешний отступ): Расстояние от границы контейнера до соседних элементов.
  • Свойство padding и margin можно задавать гибко, используя ft.padding.only() или ft.margin.symmetric():

    * ft.padding.all(10) — 10 пикселей со всех сторон. * ft.padding.symmetric(horizontal=20, vertical=10) — разные отступы по осям. * ft.padding.only(left=10, top=5) — точечная настройка.

    Expand: Заполнение пространства

    Часто требуется, чтобы элемент занимал всё доступное свободное место (например, центральная часть сайта между шапкой и подвалом). Для этого используется свойство expand.

    Свойство expand есть у любого контрола, вложенного в Row или Column. Оно работает аналогично flex-grow в CSS.

    Пример: Боковое меню и контент

    Пропорциональное разделение

    Если задать expand целочисленное значение, можно делить пространство в пропорциях.

    Пример: expand=1 для левой колонки и expand=3 для правой. Flet сложит эти числа () и выделит левой колонке ширины, а правой — .

    Практика: Создание карточки товара

    Соберем полученные знания, создав компонент карточки товара. Нам понадобятся:

  • Container для рамки и фона.
  • Column для вертикального расположения (картинка, текст, кнопка).
  • Row для цены и кнопки "Купить".
  • В этом примере мы вложили Row внутрь Column, который вложен в Container. Это стандартная практика построения интерфейсов любой сложности.

    Итоги

  • Row и Column — основные инструменты компоновки. Row выстраивает элементы горизонтально, Column — вертикально.
  • Оси выравнивания: MainAxisAlignment управляет положением вдоль главной оси (горизонталь для Row, вертикаль для Column), а CrossAxisAlignment — вдоль поперечной.
  • Container используется для визуального оформления (цвет, границы) и управления отступами (padding, margin). Он может содержать только один дочерний элемент.
  • Expand позволяет элементам занимать свободное пространство, делая интерфейс резиновым и адаптивным.