DevelNext – Графические объекты, позиционирование
Про динамическое создание объектов упоминается в документации на хабе, но я хочу упомянуть про некоторые нюансы, с которыми можно столкнуться при разработке в DN..
Документация – динамическое создание элементов.
Навигация по статье
Все графические объекты начинаются с UX: UXButton, UXLabel и т.д. Список объектов можно увидеть в подсказках.
Для добавления дочерних объектов у всех родительских элементов есть метод add (все layout панели) или ->items->add(таблица UXTableView, список UXListView).
Изображения
Для изображений существуют классы UXImage и UXImageView.
UXImage – отвечает за загрузку, хранение в памяти, сохранение графического изображения. Загружать можно по ссылке, из файла, из ресурсов, всё есть в документации.
UXImageView – отвечает за отображение содержимого UXImage.
1 2 3 4 5 6 7 8 9 10 11 |
// Загрузим изображение по ссылке $img = UXImage::ofUrl('https://pp.userapi.com/c623900/v623900473/64549/SZqwB6QZ6ZA.jpg'); // или из файла $img = new UXImage('path/to/image.jpg'); // или из ресурсов $img = new UXImage('res://.data/img/image.jpg'); $imageView = new UXImageView($img); // Добавляем в контейнер для отображения картинки $this->add($imageView); // Добавляем на форму |
Текст
Текст можно отобразить в объектах UXLabel и UXLabelEx, разница лишь в том, что последний умеет подстраиваться под размер текста, есть свойство autosize.
Текст с автоматическим переносом можно создать так:
1 2 3 4 5 |
$label = new UXLabel(str_repeat('очень ', 30) . 'длинный текст'); $label->wrapText = true; // Включаем перенос $label->leftAnchor = $label->rightAnchor = 1.0; // Закрепляем слева и справа $this->add($label); // Добавляем на форму |
Шрифт
Шрифт у объектов нельзя изменять, можно лишь присвоить свойству ->font новый объект с новым шрифтом.
1 2 3 4 5 6 |
$label = new UXLabel('text123'); $label->font->size = 16; // Так нельзя, ошибка!!! $label->font->withBold(); // Так тоже не получится // Только так: $label->font = $label->font->withBold()->withSize(16); // Будет создан новый объект UXFont |
Как подключить свой шрифт описано в отдельной статье.
Списки
За объект список отвечает класс UXListView. Содержимое списка хранится в свойстве ->items , из названия методов, думаю, можно понять, какой за что отвечает.
Можно добавлять как обычные текстовые элементы, так и объекты с изображением, панелями и т.д.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$this->listView->items->add('текст1'); $this->listView->items->add(new UXHBox()); // или несколько объектов сразу $this->listView->items->addAll([ new UXLabelEx('текст'), new UXImageView(new UXImage('path/to/image')) ]); var_dump($this->listView->items->count()); // выведет количество элементов foreach($this->listView->items as $item){ // элементы списка можно обработать в цикле } |
Таблицы
Методы у таблицы (UXTableView) схожи с методами списков (UXListView). Так же есть свойство ->items, где хранится содержимое таблицы; есть свойство ->columns (с такими же методами add, remove, etc…), где хранятся столбцы таблицы.
Отличие от списка лишь в том, что при добавлении данных нужно передать ассоциативный массив с id столбцов.
Например, есть таблица со столбцами id, name, value:
Чтоб добавить данные напишем такой код:
1 2 3 4 5 6 7 8 9 10 11 12 |
// Добавляем текстовые данные // Обратите внимание, что массив виде id_cтолбца => значение $this->table->items->add(['id' => 1, 'name' => 'Name 1', 'value' => 'Value 1']); // Также можно добавлять различные объекты // картинка $image = new UXImageView(new UXImage('res://.data/img/russian.png')); $image->size = [25,25]; // цветной текст $label = new UXLabelEx('Hello'); $label->backgroundColor = UXColor::of('#55CCCC'); $this->table->items->add(['id' => 2, 'name' => $label, 'value' => $image]); |
Для добавления столбца необходимо создать объект UXTableColumn
1 2 3 4 |
$column = new UXTableColumn; $column->text = 'Новый столбец'; $column->id = 'new_column'; $this->table->columns->add($column); |
У столбцов есть возможность сортировки содержимого, но сортировка работает совсем не так как нужно, поэтому я написал класс для сортировки таблиц – GitHub, проект
Панель табов
Класс для панели табов – UXTabView
Новые табы (UXTab) можно добавить аналогично столбцам в таблице, но есть особенность – нужно на таб добавить какую-нибудь layout-панель, чтоб добавить на таб содержимое.
1 2 3 4 5 6 7 8 9 |
$tab = new UXTab; // Создаём таб $tab->text = 'New Tab'; // Текст таба $tab->content = new UXPane; // Панель для содержимого, необязательно UXPane, можно например UXAnchorPane $tab->content->add(new UXLabel('Это новый таб')); // Добавляем текст на таб $this->tabPane->tabs->add($tab); // Добавляем таб // Меняем фокус на последний, нами созданный таб $this->tabPane->selectedIndex = $this->tabPane->tabs->count - 1; |
Добавить содержимое на конкретный таб можно так:
1 2 3 4 5 6 7 8 |
// Добавим текст на там с индексом 0 $this->tabPane->tabs->offsetGet(0)->content->add(new UXLabel('test123')); // или в цикле переберём все табы foreach ($this->tabPane->tabs as $k => $tab){ /** @var UXTab $tab **/ // Комментарий чтоб редактор отображал подсказки $tab->content->add(new UXLabel('Это таб №' . $k)); } |
Объекты, отвечающие за разметку (Layout)
UXPane – просто панель, позиционирование объектов задаётся в их параметрах x и y.
UXScrollPane – панель с поддержкой скролла, если размер содержимого больше размера панели. Особенность в том, что напрямую добавить объект $scrollPane->add() не получится. Нужно сначала создать внутри объекта контейнер или панель, от которой будет зависеть наличие скролла, а на эту панель помещать объекты
1 2 3 4 |
$scrollPane = new UXScrollPane; $scrollPane->content = new UXPanel; // Сначала создаём панель для объектов $scrollPane->content->add(new UXLabel('text')); // На панель помещаем объекты $scrollPane->content->add(new UXTextArea); |
UXAnchorPane – если объект расположен в этой панели, есть возможность указать якорь (к какому краю будет привязан объект), это свойства topAnchor, leftAnchor, rightAnchor, bottomAnchor. Например, $object->rightAnchor = 3.5 будет означать, что объект расположен на 3,5 пикселя от правого края панели.
UXVBox и UXHBox – располагают объекты вертикально или горизонтально соответственно
1 2 3 |
$box = new UXVBox([$object1, $object2, ...]); // или $box->add($object); |
UXFlowPane – Может располагать объекты по-горизонтали или по-вертикали, содержимое перемещается на новую строку, если не влазят в заданную ширину.
UXTilePane – аналогично UXFlowPane, только объекты располагаются в сетке с одинаковой шириной ячеек.
Позиционирование объектов
Для позиционирования объектов нам помогут объекты из пункта выше layout. Сами по себе объекты кнопка (UXButton), текст (UXLabel) и т.д. не могут быть позиционированы без использования layout объектов (только абсолютно – с указанием x и y), для этого их нужно разместить в UXAnchorPane или UXHBox и т.п., в зависимости от того, что нам нужно.
Внутри UXHBox и UXVBox layout объекты тоже могут позиционироваться (растягиваться) по-разному:
для UXHBox есть метод UXHBox::setHgrow($object, $rule);
для UXVBox – UXVBox::setVgrow($object, $rule);
$object – графический объект
$rule – правило, по которому будет растягиваться объект внутри layout – NEVER, ALWAYS, SOMETIMES
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// Создадим 3 панели с надписями $pane1 = new UXAnchorPane; $pane1->backgroundColor = UXColor::of('#FF0000'); $pane1->add(new UXLabel('Always')); $pane2 = new UXAnchorPane; $pane2->backgroundColor = UXColor::of('#AAAAFF'); $pane2->add(new UXLabel('Never')); $pane3 = new UXAnchorPane; $pane3->backgroundColor = UXColor::of('#00FF00'); $pane3->add(new UXLabel('Sometimes')); // Поместим объекты в горизонтальный бокс $box = new UXHBox([$pane1, $pane2, $pane3]); // Установим правила растяжения UXHBox::setHgrow($pane1, 'ALWAYS'); // Растягивать первыми по приоритету UXHBox::setHgrow($pane2, 'NEVER'); // Никогда не растягивать - значение по умолчанию у всех элементов UXHBox::setHgrow($pane3, 'SOMETIMES'); // Растягивать вторыми по приоритету // В данном примере объект-родитель - список $this->listView->items->add($box); |
Чтоб позиционировать текст или кнопку внутри бокса, их сначала нужно поместить на какой-нибудь layout (например UXAnchorPane), а layout в UXHBox.
Комбинируя объекты можно получить нужный макет с необходимым растягиванием содержимого
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
$label1 = new UXLabelEx('FirstName'); $label1->font = $label1->font->withBold(); $label1->leftAnchor = $label1->rightAnchor = 1.5; $parentL1 = new UXAnchorPane; $parentL1->add($label1); UXHBox::setHgrow($parentL1, 'ALWAYS'); $label2 = new UXLabelEx('LastName'); $label2->font = $label1->font->withItalic(); $label3 = new UXLabelEx('Description'); $label3->textColor = UXColor::of('#333'); $label3->alignment = 'CENTER'; $label3->leftAnchor = $label3->rightAnchor = 0.5; $parentL3 = new UXAnchorPane; $parentL3->add($label3); UXHBox::setHgrow($parentL3, 'ALWAYS'); UXVBox::setVgrow($parentL3, 'ALWAYS'); $hbox = new UXHBox([$parentL1, $label2]); UXVBox::setVgrow($hbox, 'ALWAYS'); $vbox = new UXVBox([$hbox, $parentL3]); UXHBox::setHgrow($vbox, 'ALWAYS'); $image = new UXImageView(new UXImage('res://.data/img/russian.png')); $image->size = [64, 64]; $mainBox = new UXHBox([$vbox, $image]); // В данном примере объект-родитель - список $this->listView->items->add($mainBox); |
Поиск объектов по селектору
В DN можно искать объекты по их css селектору (как в js). Для этого у layout объектов есть методы ->lookup и ->lookupAll
Например, найти все кнопки на форме можно так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$buttons = $this->layout->lookupAll('.button'); foreach ($buttons as $button){ /* @var UXButton $button */ var_dump([$button->id => $button->text]); } /* Вывод в консоль: array(1) { ["button"]=> string(6) "Кнопка" } array(1) { ["buttonAlt"]=> string(6) "Кнопка" } */ |
Почему-то ->lookupAll(‘*’) вызывает ошибку
Свойство graphic
У всех объектов, будь то кнопка, тест, таб, столбец таблицы, есть свойство ->graphic, с его помощью можно добавить любой графический объект
1 2 3 4 5 6 7 8 9 10 11 |
// Кнопка $this->button->graphic = new UXImageView(new UXImage('res://.data/img/1.png')); // Текст $this->label->graphic = new UXImageView(new UXImage('res://.data/img/2.png')); // Таб с индексом 1 (2й по счёту) $this->tabPane->tabs->offsetGet(1)->graphic = new UXImageView(new UXImage('res://.data/img/3.png')); // Первый столбец таблицы $this->table->columns->offsetGet(0)->graphic = new UXImageView(new UXImage('res://.data/img/4.png')); |
p.s. Статья актуальна для DevelNext версии 16.7.0
Пишу сюда потому что на посте ‘Updater — Система обновлений для проектов DevelNext’ возможность комментирования нету. Так вот, пользователь ‘lollipop’ спрашивал у вас это – ” после дейстивй с командой сборки пакета в CMD, командная строка примерно за секунду сама закрывается и файл пакета расширений не создается. Да и папки build изначально нет. Одним словом после последней команды командная строка закрывается и пакет не создается. Может вы собирете пакет для нас, чтобы сильно не мучаться, а добавите его в архив с файлами. ?…”. Но когда вы собрали и указали ссылку, эта ссылка в данный момент не работает. Можете собрать новую? За ранее благодарю!