Сделать правильно порой означает сделать единственно возможным образом.

Процесс перехода на фрейм-архитектуру оказался увлекательным и драматичным. Отсутствие у меня практического опыта использования компонентов FireMonkey вызывает желание экспериментировать и оптимизировать на этапе прототипирования. И это приводит к удивительным (для меня, привыкшему к архитектуре VCL) открытиям, которыми я готов с вами поделиться.

Базовый фрейм

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

TDataModule

Начать нужно с модуля для хранения не визуальных компонентов. Здесь мы будем размещать всё, что связано с графическими ресурсами, и то, что необходимо для подключения к базе данных. Из настроек поменяем только имя на damUIData. Напомню, что за имя отвечает свойство Name – общее свойство для всех компонентов.

TImageList

Для хранения изображений добавим на damUIData компонент класса TImageList – продвинутый инструмент, позволяющий формировать изображения в различном разрешении.

Чуть позже я расскажу о том, как этим пользоваться, а пока переименую его в imlMain и загружу в него картинки, которые можно получить из приложения Pichon for Windows. Само приложение бесплатное, скачать его можно на сайте стоковой графики icons8.com.

TFrame

Тут особых сюрпризов нет. Вместительный контейнер для всего, что душе угодно разместить на форме, но без создания формы. По сути используется для задания списка компонентов и определения их свойств в disign-time, которые потом будут создаваться и отображаться на главной форме. Все остальные визуальные компоненты я буду размешать на этом фрейме, который назову fraBaseFrame. Для того, чтобы из фрейма можно было дотянуться до картинок модуля damUIData, его нужно добавить в команду uses секции implementation. Это можно сделать вручную или с помощью меню “File” – “Use unit…”.

TToolBar

Из названия следует, что именно он нужен, чтобы создать контейнер в верхней части экрана, на котором будут находиться кнопки и метка. По умолчанию он располагается в верхней части экрана ( Align = Top ). Я переименую его в tbrTop и проверил высоту ( Height = 40 ).

❓ Чем TToolBar отличается от TPanel? Предок у них общий, назначение тоже похоже. Возможно, дело в некоторых специфичных свойствах и методах, с которыми мне ещё предстоит столкнуться.

TActionList

Все совершаемые действия удобно хранить в виде объектов в предназначенном для этого месте – в списке действий TActionList. Это традиционный для VCL компонент, но с расширенными возможностями по хранению не только обычных действий (TAction), но и действий, специфичных для различных компонентов/платформ.

Я переименовал компонент в alsMain, настроил свойство, отвечающее за картинки ( Images = damUIData.imlMain ), и добавил два действия : actBack и actHelp,

TSpeedButton

На панели TToolBar рекомендуется размещать кнопки класса TSpeedButton, хотя допустимы и другие компоненты. Не будем искушать судьбу и добавим на панель инструментов пару кнопок данного класса. Одна должна быть прижата к правому краю, другая – к левому.

❓ Немного сбило с толку свойство StyleLookup и его значения toolbuttonleft и toolbuttonrigth. На выравнивание кнопок оно не повлияло, по крайней мере в design-time. Но помогло проверенное годами свойство Anchors. Я не стал использовать Align, так как кроме кнопок на панели инструментов будет отцентрированная надпись, а видимость кнопок может меняться в зависимости от функциональности наследника базового фрейма.

Имена новых кнопок – sbtBack и sbtHelp, а их свойства Anchors установлены в [akLeft,akTop] и [akRight,akTop] соответственно. Не забываем выставить размеры в соответствии с размерами панели ( Width = 40, Height = 40 ).

❗ Попытка пойти проверенным путём, установив свойство Action у кнопки, окончилась неудачей: картинка на кнопке отображается криво – мелкая и придавлена к левому краю. Прочесывание форумов привело к тому, что самым правильным решением является размещение поверх кнопки элемента для отображения картинки, так как кнопка в FireMonkey также является контейнером для других компонентов.

TGlyph

Так как я решил использовать хранилище картинок, то мне понадобился экземпляр класса TGlyph. Принцип работы классического TImage предполагает, что изображение загружается в каждый экземпляр, что не соответствует изначальной архитектурной концепции. А TGlyph прекрасно работает со списком изображений TImageList. Более того, у него есть свойство Action, которое я тут же связал с ранее созданными действиями. И даже подумал, что кнопка-то теперь как бы и нужна вовсе – ведь при клике (нажатии) на картинку вызовется нужное действие. Но не тут то было: y TGlyph нет свойства Anchors, которое я решил использовать для привязки положения, есть только Align.

❓ И вот новая дилемма (порожденная, как выяснилось в последствии, недостаточным владением матчастью): либо отказаться от свойства Align у метки, задействовав там Anchors для центрирования, и не использовать кнопки вовсе, либо на каждую кнопку набрасывать сверху картинку. При этом картинка перекроет всю область взаимодействия и обработчики кнопки не будут срабатывать, а будет срабатывать Action, привязанный к изображению. К слову, у TImage имеется возможность становиться “прозрачной” для кликов ( HitTest = False ), а у TGlyph такого свойства нет.

Прежде чем принимать решение, я решил поэкспериментировать с различными вариантами. При этом история с дизайном и компонентами FireMonkey получила новый неожиданный поворот. Вот что мне удалось экспериментально установить:

  • Свойство Action у TGlyph не связывает картинку с действием TAction, а только устанавливает картинку из аналогичных настроек действия.
  • TGlyph является прозрачной для кликов, которые обрабатываются родительской кнопкой.
  • Если у TSpeedButton указан Action, то картинка из TActionList подтягивается в run-time даже если очистить свойство Images у кнопки в design-time

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

  • На каждую кнопку накладывать картинку, картинку привязывать к списку изображений imlMain.
  • Убрать привязку списка действий alsMain к списку изображений imlMain.
  • Каждую кнопку привязывать к действию из списка alsMain.

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

TLabel

Тут все прошло без сюрпризов, разве что вместо свойства Caption необходимо использовать Text – именно оно отвечает за отображаемый текст у компонентов FireMonkey. Для того, чтобы метка labCaption располагалась строго посредине, использовал привычные якоря ( Anchors = [akLeft, akTop, akRight, akBottom] ).

Последний штрих

Поразмыслив немного о возможных наследниках TfraBaseFrame, я решил добавить ещё одну панель инструментов, на которой будут располагаться кнопки совершения различных действий с отображаемыми данными и кнопки дополнительной навигации по фреймам. Эта панель присутствует на всех фреймах, кроме фрейма с помощью, но как знать – может и там она тоже пригодится в будущем. Переименовываем её в tbrBottom и меняем расположение ( Align = Bottom ). Базовый фрейм готов!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *