Всплывающие формы в XE5

Posted by on in Blogs

TCommonCustomForm.FormStyle

В XE5, вместо свойств StaysOpen, ShowActivated и TopMost появилось свойство FormStyle. Это свойство управляет поведением формы как и аналогичное свойство в VCL (не путайте со StyleBook, которое управляет визуальными стилями формы). Может принимать одно из трех значений:

TFormStyle = (fsNormal, fsPopup, fsStayOnTop);

Смысл fsNormal и fsStayOnTop довольно очевиден. Это обычная форма и форма которая находится всегда поверх обычных форм. Если раньше было установлено свойство TopMost, то FormStyle получит значение TFormStyle.fsStayOnTop.
Два значения fsMDIForm и fsMDIChild отсутствуют, т. к. эти значения могли бы использоваться только в Windows.

Интерес я думаю представляет значение fsPopup. Это особая форма которая используется в комбинированных списках и меню. Если раньше одно из свойств StaysOpen, или ShowActivated имело значение False, то FormStyle получит значение TFormStyle.fsPopup.

Всплывающая форма имеет отличное от других форм поведение:

    • Не может быть активной. В классе TScreen, всплывающие формы находятся в отдельном списке, см. TScreen.PopupForms и TScreen.PopupFormCount.
    • На мобильных платформах обычные формы всегда находятся в полноэкранном режиме, но к всплывающим формам это не относится.
    • Не остаётся видимой длительное время. Если кликнуть мышью (или пальцем на тачпаде) вне границ всплывающей формы, то она закроется. На экране может быть несколько всплывающих форм, связанных (или не связанных) как родительская-дочерняя. Если кликнуть на одну из всплывающих форм, то закроются все всплывающие формы кроме этой формы и всех её родителей.

Для всплывающих форм, также характерны следующие значения свойств:

BorderStyle := TFmxFormBorderStyle.bsNone; // Отсутствует рамка окна
Popup.Transparency := True;  // Форма имеет прозрачный фон

TCommonCustomForm.ParentForm

Для определения "родственных связей" форм, добавлено свойство ParentForm. Значение этого свойства устанавливается, когда Вы меняете свойство Parent. Если объект Parent является формой, он же будет использован в качестве ParentForm, иначе будет определена форма на которой лежит объект Parent.
После изменения ParentForm выполняется виртуальный метод DoParentFormChanged.

Надо отметить, что изменение таких свойств как FormStyle, BorderStyleParentForm, приводит к пересозданию формы и всех контролов на ней и всех дочерних форм. Поэтому я не рекомендую менять эти свойства в Run-time, после того как форма уже была отображена на экране.

TCustomPopupForm

Для упрощения создания всплывающих форм, создан специальный класс форм TCustomPopupForm, который используется в TPopup, TComboEdit, TPopupBox, TMenuBar и т.п. У форм данного класса по умолчанию нет рамки и фона. После закрытия происходит автоматическое разрушение. При создании не производится поиск fmx-файла формы, т. е. этот класс ориентирован только на работу в Run-time.

Поскольку у форм данного класса не видны ни рамка ни фон и они не должны выходить за границы экрана, физические координаты окна не имеют большого практического значения. Управление расположением формы осуществляется с помощью других свойств: PlacementPlacementTargetPlacementRectangle, Size. Самостоятельно менять Position, Height, Width не надо.

Экземпляры таких форм создаются с использованием конструктора:

constructor Create(AOwner: TComponent; AStyleBook: TStyleBook = nil; APlacementTarget: TControl = nil); reintroduce;

Здесь AStyleBook указывает стили используемые формой, а APlacementTarget указывает контрол рядом с которым должна появиться форма.

PlacementTarget — некоторый контрол в окрестностях которого, определенным образом располагается форма (здесь и далее для обозначения такого размещения позвольте использовать слово "прилипать"). Если он задан, то расчет экранных координат формы осуществляется относительно данного контрола, иначе относительно левого верхнего угла экрана.

PlacementRectangle — координаты прямоугольника к которому осуществляется "прилипание" формы. Расчет экранных координат PlacementRectangle, осуществляется относительно PlacementTarget если он задан, иначе относительно левого верхнего угла экрана.

    • Если PlacementRectangle не задан (ширина, или высота равны 0), но задан PlacementTarget, то используются его координаты и размеры.
    • Если не задан ни PlacementRectangle, ни PlacementTarget то "прилипание" левого верхнего угла формы осуществляется к курсору мыши.

ScreenPlacementRect — экранные координаты прямоугольника к которому осуществляется "прилипание" с учетом PlacementTarget и PlacementRectangle. На рисунке обозначен малиновым цветом.

Placement — вариант размещения формы. В большинстве случаев для определения координат формы также используется прямоугольник ScreenPlacementRect.

    • plBottom — форма снизу, если выходит за границы экрана, то сверху. Этот вид расположения обычно используется в комбобоксах.
    • plTop — форма сверху (см. картинку), если выходит за границы экрана, то снизу.
    • plLeft — форма слева, если выходит за границу экрана, то справа.
    • plRight — форма справа, если выходит за границу экрана, то слева. Этот вид расположения обычно используется в меню.
    • plCenter — форма по центру.
    • plBottomCenter — форма снизу и посередине.
    • plTopCenter — форма сверху и посередине.
    • plLeftCenter — форма слева и посередине.
    • plRightCenter — форма справа и посередине.
    • plAbsolute — для определения координат формы используется PlacementRectangle, при этом PlacementTarget игнорируется (используются координаты относительно левого верхнего угла экрана). Если ширина, или высота PlacementRectangle равны 0, то используются свойство Size.
    • plMouse — левый верхний угол прилипает к курсору мыши. PlacementRectangle и PlacementTarget игнорируется. Для определения размера используется свойство Size.
    • plMouseCenter — центр прилипает к курсору мыши. PlacementRectangle и PlacementTarget игнорируется. Для определения размера используется свойство Size.

На этом рисунке изображена всплывающая форма в которую помещен прямоугольник TRectangle с эффектом тени TShadowEffect. Прямоугольник выравнивается по всей клиентской области alClient. Различными цветами представлены некоторые важные свойства. Проект Вы можете загрузить здесь.

Padding — это свойство как и в обычной форме задает отступы от краёв клиентской области формы. По этим отступам будут выравниваться все контролы на форме. На рисунке это серый квадрат (с зеленой рамкой). По умолчанию используются значение 8, чтобы эффекты (например тень) не обрезались физическими границами окна.

Size — размер рабочей области формы. Как видно на рисунке физические размеры окна (красный пунктир) представляют малый интерес. Данное свойство (зеленый пунктир) задает те размеры по которым будут выравниваться все контролы. Размеры формы ClientWidth, ClientHeight устанавливаются автоматически с учетом Size и Padding. Если задано свойство PlacementRectangle и Placement имеет значение plAbsolute, то Size игнорируется.

ContentPadding — задает отступы от рабочей области формы, к которым осуществляется "прилипание".

ScreenContentRect — экранные координаты прямоугольника, к которому осуществляется "прилипание". Это прямоугольник внутри которого расположено полезное содержимое формы. Некоторые декоративные элементы (например треугольничек в CalloutPanel) могут вылезать за границы формы, или на кнопку.

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

DragWithParent — это свойство указывает, надо ли перемещать форму после того как она была показана. Например: если Placement имеет значение plMouse или plMouseCenter то форма будет перемещаться вслед за курсором мыши. На мобильных устройствах, после смены ориентации (портрет/ландшафт) форма будет менять расположение чтобы не оказаться частично за пределами экрана.

Извините получилось довольно много букв, надеюсь что хоть часть текста оказалась понятной.



Comments

  • Guest
    Dmitry Petukhov Saturday, 7 September 2013

    Сергей, спасибо за обстоятельное изложение! Всплывающие окна - важный и довольно удобный компонент практически всех современных операционых сред и браузеров.

  • Guest
    Sergey Smetanin Monday, 9 September 2013

    Спасибо! Все доступно.
    >> Проект Вы можете загрузить здесь.
    Unavailable Submission!

  • Guest
    Vsevolod Leonov Monday, 9 September 2013

    Спасибо, отличная статья!

    Можно ли форму использовать как "диалоговую" на мобильных устройствах? (Некоторые разработчики хотят тем самым авторизацию получить от пользователя).

    На ХЕ4 Transparent форме давало лишь чёрный фон. Сформулирую поточнее: диалоговые формы? :)

  • Guest
    Sergey Roschin Monday, 9 September 2013

    Сформулирую еще точнее: "модальные формы" :) Увы в общем случае нет. Как сказано в статье всплывающие формы идут отдельным списком, не бывают активными и поэтому не получают сообщения от клавиатуры. Почему так сделано? Потому что например в MAC OS окна диалога выдвигаются из активного окна. Забавно выглядит, когда окно сообщения вываливается из выбранного пункта меню и тут же закрывается вместе с ним. В мобильных же платформах всплывающие формы предназначены в основном для замены экранной клавиатуры.
    Есть еще компонент TPopup с "волшебным" методом PopupModal, который позволит отобразить не всплывающую и не полноэкранную форму. Увы для Андроида это пока не работает.
    Вообще из-за различий всяких фич на разных платформах приходится сводить фантазию к некоторому разумному минимуму. Такие дела :(

  • Guest
    Sergey Roschin Thursday, 12 September 2013

    >>Unavailable Submission!
    Извините за задержку с ответом, раздачей прав доступа занимаюсь не я. Сейчас вроде бы стало возможно скачивать.

    P.S. И спасибо за добрые слова.

  • Guest
    David Berneda Friday, 13 September 2013

    Great ! Thanks !
    I'll try to use this to implement hints (tooltips) for TeeChart controls.

    (mouse over for desktop, touch for mobile)

    regards!
    david

  • Guest
    zhukovsd Monday, 16 September 2013

    Добрый день. Описанное в статье это хорошо и здорово, но недавно имел несчастье поработать с TPopup в Delphi XE3.

    На попапе (staysopen = false) лежат лейблы, текст на которых может меняться, когда попап скрыт. При определенной последовательности действий по показыванию/скрытию попапа и изменению текста на лейбле может вылететь Access Violation в методе TTextLayoutGDIPlus.DoRenderLayout юнита FMX.Canvas.GDIP. Происходит это из-за невалидного указателя на TCanvasGdiPlus(FCanvas).FGPFamily. Как и почему это происходит - я понять не смог. Удалось воспроизвести это на тестовом проекте с одим попапом (лейбл внутри) и баттонами для управления попапом и текстом лейбла.

    На Mac OS всё ещё лучше - приложение просто падает на автоматическом закрытии попапа.

    С уважением и надеждой на светлое будущее FMX.

  • Guest
    Sergey Roschin Monday, 16 September 2013

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

  • Guest
    zhukovsd Thursday, 19 September 2013

    Тестовые проекты с ошибками и их описаниями выложил архивом по ссылке:
    https://docs.google.com/file/d/0B6rVdsytRXunOTIzT0hoOEhZMUk/edit?usp=sharing

    Для загрузки нажмите "файл -> скачать".

    Для связи со мной, если потребуется, используйте почту zhukovsd [at] gmail [dot] com

  • Guest
    zhukovsd Thursday, 19 September 2013

    Извиняюсь, вот корректная ссылка

    https://docs.google.com/file/d/0B6rVdsytRXunclJPRzNpWDNMRjA/edit?usp=sharing

  • Guest
    Sergey Roschin Thursday, 19 September 2013

    Спасибо, посмотрю.

  • Guest
    vadim Thursday, 6 March 2014

    XE5 как менять фон у TEdit?

    Гуглил 24 часа. Нашел неработающий способ:
    BckObject := Memo1.FindStyleResource('background');
    if Assigned(BckObject) and (BckObject is TSubImage) then
    begin
    TSubImage(BckObject).Source := nil;
    end;
    Причем TSubImage на в официальном хелпе xe5 описан. А в исходнике его нет.

  • Guest
    Sergey Roschin Thursday, 6 March 2014

    vadim, какое отношение имеет фон в Memo к теме статьи?

  • Please login first in order for you to submit comments
  • Page :
  • 1

Check out more tips and tricks in this development video: