Textual: создание пользовательского чекбокса в Python

Сегодня разбираем материал blog.pythonlibrary.org о теме «Textual — создаём пользовательский чекбокс». Материал полезен тем, кто хочет быстро понять суть темы и перевести идеи в прикладные действия.


Textual — это пакет для создания пользовательских интерфейсов на Python, позволяющий разрабатывать графические интерфейсы непосредственно в терминале без браузеров и оконных фреймворков

Textual — создаём пользовательский чекбокс: ключевой визуальный блок

В Textual есть множество виджетов, и в этом руководстве мы сосредотачиваемся на чекбоксе

Чекбоксы служат для выбора между двумя состояниями. Они возвращают True, если отмечены, и False, если не отмечены. Чекбокс может служить визуальным индикатором включённой или отключённой опции

В этом руководстве вы узнаете:

  • Как создать стандартный чекбокс
  • Как настроить виджет чекбокса

Как создать стандартный чекбокс

Начинайте с виджета по умолчанию, чтобы проверить, подходит ли он вам. Откройте свою любимую Python IDE и создайте файл с кодом:

from textual.app import App, ComposeResult
from textual.containers import VerticalScroll
from textual.widgets import Checkbox
class CheckboxApp(App[None]): def compose(self) -> ComposeResult: with VerticalScroll(): yield Checkbox("Mike")
def on_checkbox_changed(self, event: Checkbox.Changed) -> None: self.notify(f"Checkbox value: {event.value}")
if __name__ == "__main__": CheckboxApp().run()

Приведённый выше пример основан на примере кода из документации Textual. Использовать контейнер VerticalScroll здесь не обязательно, но это удобно при добавлении серии виджетов в один контейнер

Основное внимание следует уделить самому Checkbox. Здесь вы просто возвращаете его из compose() с помощью yield, а затем перехватываете событие Checkbox.Changed. Когда событие срабатывает, вы отображаете пользователю уведомление о том, что он изменил значение чекбокса

Этот код создаст чекбокс с меткой и символом «X» в состоянии по умолчанию.

Однако если вы хотите, чтобы границы виджета были всегда видны, нужно добавить рамку к виджету

Но что если вы хотите, чтобы чекбокс был полностью пустым, а не отображал затемнённый «X»? Именно этому вы научитесь в следующем разделе.

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

Почему стандартный чекбокс не всегда подходит

Если у вас фон по умолчанию или тёмный фон, затемнённый символ может стать проблемой с контрастностью.

Многие GUI-инструментарии отображают чекбокс пустым в состоянии False, поэтому поведение Textual, показывающее затемнённый «X», может сбивать с толку пользователей, привыкших к классическим интерфейсам.

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

Как настроить виджет чекбокса

Создайте новый файл Python в вашей IDE и введите следующий код:

class CustomCheck(Checkbox): BUTTON_INNER = " "
def toggle(self) -> None: if self.value: CustomCheck.BUTTON_INNER = " " else: CustomCheck.BUTTON_INNER = "X" self.value = not self.value return self
class CheckboxApp(App[None]): #CSS_PATH = "checkbox.tcss" def compose(self) -> ComposeResult: check = CustomCheck("Mike") with VerticalScroll(): yield check

Когда вы хотите настроить уже существующий виджет в Textual, вы почти всегда будете создавать его подкласс (subclass). Здесь вы создаёте подкласс класса Checkbox, чтобы получить новый класс CustomCheck. Затем вы переопределяете атрибут класса BUTTON_INNER, а также метод toggle().

Если заглянуть в исходный код Textual, можно обнаружить, что BUTTON_INNER по умолчанию равен «X», поэтому здесь вы устанавливаете его по умолчанию в пустую строку. Затем вы обновляете toggle() так, чтобы «X» появлялся при отметке чекбокса и исчезал при снятии отметки.

Другое изменение — использование нового класса виджета в коде вашего приложения: вместо стандартного Checkbox вы создаёте экземпляр CustomCheck.

Как добавить рамку через Textual CSS

Чтобы увеличить видимость виджета, вы можете добавить рамку с помощью Textual CSS (каскадных таблиц стилей для Textual). Создайте новый файл с именем checkbox.tcss и добавьте в него следующий код:

CustomCheck { border: round green;
}

Убедитесь, что вы сохранили этот файл в той же папке, что и ваш файл Python.

Теперь раскомментируйте строку #CSS_PATH = "checkbox.tcss" в классе CheckboxApp, убрав символ #. После этого Textual подхватит стили автоматически.

При запуске этого кода вы увидите следующее: чекбокс с зелёной скруглённой рамкой, пустой по умолчанию и отображающий «X» при активации.

Отлично! Теперь у вас есть пользовательский чекбокс с нужным поведением и визуальным оформлением.

Типичные ошибки при создании пользовательского чекбокса

Работая с подобными задачами, я замечал несколько ошибок, которые встречаются чаще всего.

Файл стилей не найден. Если вы указали CSS_PATH, но файл .tcss лежит в другой папке, Textual выдаст ошибку при запуске. Убедитесь, что путь указан корректно или используйте абсолютный путь

Атрибут BUTTON_INNER изменяется глобально. Поскольку BUTTON_INNER — это атрибут класса, а не экземпляра, его изменение через CustomCheck.BUTTON_INNER затронет все экземпляры этого класса одновременно. Если вам нужно несколько независимых чекбоксов, стоит переработать логику и хранить состояние символа на уровне экземпляра.

Метод toggle() не вызывает родительский класс. Когда вы переопределяете toggle(), убедитесь, что понимаете, какую логику родительского класса вы заменяете. В данном примере вся логика переключения написана заново, что намеренно — но в более сложных случаях это может привести к потере функциональности.

Отсутствие рамки делает виджет малозаметным. Без явного стиля чекбокс может сливаться с фоном терминала. Добавление border через .tcss — простой способ сделать виджет визуально различимым.

Как применить эти знания к другим виджетам

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

Чтобы успешно модифицировать любой виджет Textual, нужно внимательно изучить его исходный код. Репозиторий Textual на GitHub хорошо структурирован: каждый виджет — отдельный файл, атрибуты класса вынесены наверх и легко читаются.

Вот общий алгоритм:

  1. Найдите нужный виджет в исходном коде Textual
  2. Определите атрибуты класса, которые управляют внешним видом или поведением
  3. Найдите методы, которые реализуют нужную вам логику
  4. Создайте подкласс и переопределите только то, что требует изменений
  5. Протестируйте поведение на нескольких экземплярах виджета

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

Подведение итогов

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

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

Не сдавайтесь — в конце концов вы добьётесь своего, и результат будет стоить потраченного времени

Узнать больше

Если эта статья показалась вам интересной и вы хотите узнать больше о Textual, ознакомьтесь со следующими ресурсами:

  • Сайт Textual
  • Creating TUI Applications with Textual and Python (книга)

Ответы на эти вопросы могут быть для вас полезными

Можно ли использовать несколько пользовательских чекбоксов одновременно?

Да, но нужно учитывать, что BUTTON_INNER — атрибут класса, а не экземпляра. Если вам нужны независимые чекбоксы с разным состоянием символа, стоит хранить символ на уровне экземпляра через self._inner и переопределить соответствующий метод рендеринга.

Обязательно ли использовать файл .tcss для стилизации?

Нет. Textual позволяет задавать стили и через атрибут DEFAULT_CSS прямо внутри класса виджета. Файл .tcss удобен для больших приложений, где стили нужно вынести отдельно и переиспользовать.

Что произойдёт, если не переопределить метод toggle()?

Стандартный toggle() переключит значение self.value, но символ BUTTON_INNER останется тем, что вы задали по умолчанию — пустой строкой. Чекбокс будет переключаться, но визуально оставаться пустым в обоих состояниях.

Можно ли изменить символ чекбокса на что-то отличное от «X»?

Да. В методе toggle() вы можете задать любой символ или даже эмодзи вместо "X". Главное — убедиться, что символ корректно отображается в вашем терминале и не нарушает выравнивание виджета.

Работает ли этот подход с другими виджетами Textual, например с кнопками или переключателями?

Да, принцип создания подкласса и переопределения атрибутов и методов универсален для всех виджетов Textual. Конкретные атрибуты и методы будут отличаться — их нужно искать в исходном коде соответствующего виджета.

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x