Изучение библиотеки LVGL. Базовые свойства объектов
В данной статье мы продолжим изучение библиотеки LVGL и рассмотрим базовые свойства объектов.
Изучение библиотеки LVGL. Базовые свойства объектов
29.03.2024 в 11:50   1487 0
Версия для печати

Изучение библиотеки LVGL. Базовые свойства объектов

Введение

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

Теперь мы глубже погрузимся в изучение библиотеки и рассмотрим такой её важный элемент  как объекты. Объекты - это основные элементы пользовательского интерфейса, такие как кнопки, полосы прокрутки, метки и т.д. В данной статье мы сфокусируемся на базовых свойствах всех типов объектов. Узнаем, как их создавать , изменять размеры, параметры и свойства. Понимание этих основных свойств объектов позволит нам эффективно использовать LVGL для создания красивых и функциональных пользовательских интерфейсов на микроконтроллерах.

Общие сведения по объектам

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

lv_obj_set_align(obj, LV_ALIGN_CENTER);
lv_obj_set_pos(obj, 10, 20);

// Или в одной функции
lv_obj_align(obj, LV_ALIGN_CENTER, 10, 20); 

Каждый объект имеет уникальный идентификатор, который используется для обращения к нему из программного кода. Объекты могут быть созданы как на верхнем уровне экрана, так и вложены друг в друга для создания более сложных интерфейсов.

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

Типы объектов в LVGL

LVGL предоставляет множество типов объектов или, так называемых виджетов, для создания пользовательских интерфейсов. Некоторые из наиболее распространенных типов объектов в LVGL:

  • Кнопка (lv_btn) - элемент интерфейса, который может быть нажат пользователем.
  • Метка (lv_label) - объект, который отображает текст на экране.
  • Изображение (lv_img) - объект, который отображает изображение на экране.
  • Список (lv_list) - объект, который позволяет выбирать один или несколько элементов из списка.
  • Ползунок (lv_slider) - объект, который позволяет пользователю выбирать значение из диапазона.
  • Поле ввода (lv_textarea) - объект, который позволяет пользователю вводить текст.
  • Таблица (lv_table) - объект, который представляет собой таблицу с ячейками.

Каждый из этих объектов имеет ряд свойств:

  • Базовые свойства. Размер, положение, видимость и т.п. Они есть у всех объектов. 
  • Специальные  свойства. Шрифт, формат текста, действие при нажатии, рисунок и т.п. Они зависят от конкретного объекта. У других виджетов их может и не быть.

В рамках данной статьи мы рассмотрим только базовые свойства присущие всем объектам LVGL.

Объявление объекта

Ссылки на все объекты выполняются с использованием lv_obj_t указателя в качестве дескриптора. Этот указатель впоследствии может быть использован для установки или получения атрибутов объекта.

В общем виде это может выглядеть так:
lv_obj_t * btn1; 

В дальнейшем обращаться к данному объекту мы сможем по имени указателя btn1.

Создание и удаление объекта

У каждого виджета есть своя собственная функция create с прототипом, подобным этому:

lv_obj_t * lv_<виджет>_create(lv_obj_t * родитель, <другие параметры );,,,

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

Возвращаемое значение представляет собой указатель на созданный объект с lv_obj_t * тип.

Например, для создания кнопки используется следующий код:

lv_obj_t * btn1 = lv_btn_create(screenMain);

В данном случаем, мы создаем объект типа lv_btn, родителем котором является объект screenMain и присваиваем ссылку на него указателю btn1.

В дальнейшем все действия с объектом можно выполнять с использованием его указателя. Например для изменения ширины кнопки можно использовать функцию:
lv_obj_set_width(btn1, 120); //ширина

Здесь мы для объекта на который ссылается указатель btn1, устанавливаем ширину 120 пикселей.

Также важно понимать, что объекты созданные таким образом, доступны лишь в пределах функции в которой они были объявлены. То есть, если вы, например, в функции void setup() создадите объект btn1, то в дальнейшем при попытке обратиться к нему из другой функции вы получите ошибку. Чтобы этого избежать, можно объявить глобальную ссылку на объект. Как, например, в этом примере:

#include "touch.h"
lv_obj_t * btn1;
lv_obj_t * screenMain;
...
...
...
void setup()
{ ...
...
screenMain = lv_obj_create(NULL);
btn1 = lv_btn_create(screenMain);
...
...
}

В результате, мы создадим глобальные ссылки screenMain и btn1 и, после создания объектов, можем обращаться к ним из любого места программы. Но данный подход имеет существенный минус. Объекты постоянно будут висеть в оперативной памяти устройства и отбирать драгоценные килобайты.

Для немедленного удаления объекта используется функция lv_obj_del(lv_obj_t * obj). Она удаляет объект и все его дочерние элементы. Например, для удаления btn1 из предыдущего примера достаточно написать:

lv_obj_del(btn1);

Если по какой-либо причине вы не можете удалить объект немедленно, вы можете использовать lv_obj_del_async(obj) который выполнит удаление при следующем вызове lv_timer_handler(). Это полезно, например, если вы хотите удалить родительский объект в LV_EVENT_DELETE обработчике дочернего объекта.

Вы можете удалить все дочерние элементы объекта (но не сам объект) с помощью lv_obj_clean(obj).

Вы можете использовать lv_obj_del_delayed(obj, 1000) для удаления объекта через некоторое время. Задержка выражается в миллисекундах.

Родительско-дочерняя структура

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

Если позиция родительского элемента изменяется, дочерние элементы будут перемещаться вместе с ним. Следовательно, все координаты указываются относительно родительского объекта. Это иллюстрирует следующий код:

lv_obj_t * parent = lv_obj_create(lv_scr_act()); /*Создадим родительский объект на текущем экране*/
lv_obj_set_size(parent, 100, 80); /*Установим размер родительского объекта*/

lv_obj_t * obj1 = lv_obj_create(parent); /*Создадим объект на предварительно созданном родительском объекте*/
lv_obj_set_pos(obj1, 10, 10); /*Установить позицию дочернего объекта относительно родительского*/

Схематичный результат выполнения программы вы можете увидеть на картинке ниже:

cp1

Теперь попробуем изменить позицию родительского объекта:

lv_obj_set_pos(parent, 50, 50); /*Перемещаем родителя. Дочерний элемент переместится вместе с ним*/

Дочерний элемент также изменит свое положение вместе с родительским:

cp2

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

lv_obj_set_x(obj1, -30); /* Немного отодвинем дочерний элемент влево*/

На экране вы увидите следующее:

cp3

Часть дочернего элемента за пределами родительского невидима. Это поведение может быть изменено с помощью lv_obj_add_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE);. Тогда картинка на экране будет выглядеть несколько иначе:

cp4

Дисплей и экраны

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

Когда вы создадите подобный экран lv_obj_t * screen = lv_obj_create(NULL), вы можете сделать его активным с помощью lv_scr_load(screen)

Функция lv_scr_act() дает вам указатель на активный экран.

Если у вас несколько дисплеев, важно знать, что функции экрана работают на самом последнем созданном дисплее или на том, который явно выбран с помощью lv_disp_set_default.

Чтобы узнать экран к которому относится объект, используйте функцию lv_obj_get_screen(obj) .

Размер и положение объекта

Размер объекта могут быть изменены по отдельным осям с помощью
lv_obj_set_width(obj, new_width) и lv_obj_set_height(obj, new_height)

Размер по обеим осям может быть изменён одновременно с помощью
lv_obj_set_size(obj, new_width, new_height). Например:

lv_obj_set_width(btn1, 100); //устанавливаем ширину 100 пикселей для объекта btn1
lv_obj_set_height(btn1, 60); //Устанавливаем высоту 60 пикселей для объекта btn1
lv_obj_set_size(btn1, 100, 60); //Устанавливаем для объекта btn1 ширину 100 и высоту 60 пикселей

Вы можете задать положение относительно родительского объекта с помощью
lv_obj_set_x(obj, new_x) и lv_obj_set_y(obj, new_y)

Или для обеих осей одновременно с помощью
lv_obj_set_pos(obj, new_x, new_y). Например:

lv_obj_set_x(btn1, 50); //устанавливаем для объекта btn1 положение по оси Х равным 50 пикселям
lv_obj_set_y(btn1, 60); //устанавливаем для объекта btn1 положение по оси У равным 60 пикселям
lv_obj_set_pos(btn1, 50, 60); //устанавливаем координаты для объекта btn1 по оси X=50, а по оси Y=60 
 

Выравнивание

Вы можете выровнять объект по его родительскому элементу с помощью lv_obj_set_align(obj, LV_ALIGN_...). После этого все настройки x и y будут соответствовать установленному режиму выравнивания. Например, это приведет к смещению объекта на 10 и 20 пикселей от центра его родительского объекта:

lv_obj_set_align(obj, LV_ALIGN_CENTER);
lv_obj_set_pos(obj, 10, 20);

// Или в одной функции
lv_obj_align(obj, LV_ALIGN_CENTER, 10, 20); 

Для выравнивания одного объекта относительно другого используется функция: lv_obj_align_to(obj_to_align, obj_reference, LV_ALIGN_..., x, y)

Например, чтобы выровнять текст под изображением:

lv_obj_align_to(text, image, LV_ALIGN_OUT_BOTTOM_MID, 0, 10)

Существуют следующие типы выравнивания:

align

Дополнительные атрибуты объектов

Есть некоторые атрибуты, которые могут быть включены / отключены с помощью lv_obj_add/clear_flag(obj, LV_OBJ_FLAG_...):

  • LV_OBJ_FLAG_HIDDEN Делает объект скрытым. (Как будто его там вообще не было)
  • LV_OBJ_FLAG_CLICKABLE Делает объект интерактивным, то есть реагирующим на касание или нажатие кнопки мыши
  • LV_OBJ_FLAG_CLICK_FOCUSABLE При нажатии на объект добавляется сфокусированное состояние
  • LV_OBJ_FLAG_CHECKABLE При нажатии на объект переключается его состояние. По логике похоже на чекбокс.
  • LV_OBJ_FLAG_SCROLLABLE включить/выключить прокрутку объекта если он не вмещается на экран
  • LV_OBJ_FLAG_SCROLL_ELASTIC Плавная прокрутка, но с меньшей скоростью
  • LV_OBJ_FLAG_SCROLL_MOMENTUM Прокрутка обладает инерцией
  • LV_OBJ_FLAG_SCROLL_ONE Разрешить прокрутку только одного дочернего объекта с возможностью привязки
  • LV_OBJ_FLAG_SCROLL_CHAIN_HOR Разрешить распространение горизонтальной прокрутки на родительский объект
  • LV_OBJ_FLAG_SCROLL_CHAIN_VER Разрешить распространение вертикальной прокрутки на родительский объект
  • LV_OBJ_FLAG_SCROLL_CHAIN  объединяет в себе действие этих двух флагов (LV_OBJ_FLAG_SCROLL_CHAIN_HOR | LV_OBJ_FLAG_SCROLL_CHAIN_VER)
  • LV_OBJ_FLAG_SCROLL_ON_FOCUS Автоматически прокручивать объект, чтобы сделать его видимым при фокусировке
  • LV_OBJ_FLAG_SCROLL_WITH_ARROW Разрешить прокрутку сфокусированного объекта с помощью клавиш со стрелками
  • LV_OBJ_FLAG_SNAPPABLE Если привязка прокрутки включена на родительском объекте, он может привязываться к этому объекту
  • LV_OBJ_FLAG_PRESS_LOCK Сохранять нажатое состояние объекта, даже если курсор или  точка касания вышли за пределы объекта
  • LV_OBJ_FLAG_EVENT_BUBBLE Распространять события и на родительский объект
  • LV_OBJ_FLAG_GESTURE_BUBBLE Распространить жесты на родительский объект
  • LV_OBJ_FLAG_ADV_HITTEST Более точное определение координат при касании объекта. Например для объектов сложной формы
  • LV_OBJ_FLAG_IGNORE_LAYOUT Игнорировать слои  расположения объектов. То есть не позволять перекрывать его другими объектами
  • LV_OBJ_FLAG_FLOATING Не прокручивать объект, когда прокручивается родительский объект и разместить его поверх всех объектов. 
  • LV_OBJ_FLAG_OVERFLOW_VISIBLE Не обрезать дочерний объект если он выходит за границы родительского
  • LV_OBJ_FLAG_LAYOUT_1 Пользовательский флаг, свободно используемый макетами
  • LV_OBJ_FLAG_LAYOUT_2 Пользовательский флаг, свободно используемый макетами
  • LV_OBJ_FLAG_WIDGET_1 Пользовательский флаг, свободно используемый виджетом
  • LV_OBJ_FLAG_WIDGET_2 Пользовательский флаг, свободно используемый виджетом
  • LV_OBJ_FLAG_USER_1 Пользовательский флаг, свободно используемый пользователем
  • LV_OBJ_FLAG_USER_2 Пользовательский флаг, свободно используемый пользователем
  • LV_OBJ_FLAG_USER_3 Пользовательский флаг, свободно используемый пользователем
  • LV_OBJ_FLAG_USER_4 Пользовательский флаг, свободно используемый пользователем

Небольшой пример:


/*Спрячем объект*/
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);

/*Сделаем объект неинтерактивным*/
lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE);
 

Группировка объектов

Объекты добавляются в группу с помощью lv_group_add_obj(group, obj), и вы можете использовать lv_obj_get_group(obj), чтобы увидеть, к какой группе принадлежит объект.

lv_obj_is_focused(obj) возвращает, сфокусирован ли объект в данный момент на своей группе или нет. Если объект не добавлен в группу, функция вернет false.

Расширение области нажатия

По умолчанию на объекты можно нажимать только в пределах их ограниченной области. Однако её можно расширить с помощью lv_obj_set_ext_click_area(obj, size).

Заключение

В данной статье мы углубились в изучение объектов библиотеки LVGL и изучили базовые свойства, присущие всем объектам. Мы научились создавать объекты и использовать функции для изменения их параметров, таких как размер, положение, родительско-дочерние отношения и т.д. Также мы рассмотрели их структуру  и поняли, как изменения параметров влияют на внешний вид и функциональность. Это позволит нам создавать более сложные и интерактивные пользовательские интерфейсы с помощью библиотеки LVGL на микроконтроллерах.
Материал также доступен на моем канале: Яндекс Дзен и в группе ВК
Категория: LVGL (Light and Versatile Graphics Library) | Добавил: :, (22.04.2023)
Просмотров: 1487 | Теги: ESP8266, Arduino IDE, ESP32, TFT_eSPI, LVGL | Рейтинг: 5.0/1
Поделиться:
Всего комментариев: 0
avatar