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

В первой части цикла статей «Firemonkey. От простого к сложному» мы остановились на том, что рассмотрели свойства компонентов Firemonkey, которые присутствуют практически в каждом компоненте FMX, чтобы уже далее к ним каждый раз не возвращаться и сосредоточиться только на уникальных свойства компонентов и работе с ними.

Сегодня продолжим начатую тему и рассмотрим некоторые особенности работы с компонентами, которые расположены на вкладке Standard. Несмотря на то, что 95% всех компонентов, расположенных на этой вкладке нам знакомы ещё из VCL, иногда приходится «по горячим следам», уже работая с компонентом, открывать для себя какие-то новые моменты по работе с ним. Что ж, будем двигаться от простого к сложному и ликвидировать подобные мелкие проблемки.


Раздел 1. Компоненты Firemonkey

2. Списки

Что может быть проще, чем использовать какой-нибудь компонент с этой вкладки? Ведь это та самая первая вкладка на палитре компонентов с которой начинается «программистское детство» — метки с выводом фразы «Hello World!», кнопочка TButton с парой Edit’ов на форме для решения суперсложных квадратных уравнений..ностальгия ё-маё.. Теперь нам придётся снова немного вернуться в «детство», но уже посмотреть на компоненты вкладки Standard более осмысленным взором и в контексте работы с FMX. А начнем мы обзор с компонента TListBox.

Компонент TListBox

Свойство Columns

Давайте посмотрим внимательно на свойства этого компонента. Во-первых, если рассматривать уже известные нам по VCL свойства этого компонента, то мы увидим, что изменилось свойство Columns. Теперь оно по умолчанию имеет значение 1. А вместе с ним и поведение самого компонента TListBox. Вот простой пример.

Создайте в Delphi XE2 новую группу проектов и в этой группе 1 проект — VCL Application, а второй — Firemonkey HD Application. На главные формы проектов бросаем по ListBox’у и устанавливаем им одинаковые свойства Columns = 1. А также заносим в свойство Items..ну скажем по 15 строк.

А теперь меняем постепенно у этих ListBox’ов высоту. Что происходит с ListBox из VCL? Он каждый раз как элементы списка не умещаются по высоте начинает их сдвигать вправо и получается в итоге «что-то с чем-то». Вот, например, какой получился у меня ListBox после того как по высоте стали умещаться всего 3 элемента списка:

Если запустить приложение, то, чтобы добраться до конца списка надо будет четырежды его «проскролить». Конечно, можно настроить Columns как нам надо, самим прорисовывать весь список и т.д. и т.п., но суть не в этом. Смотрим как выглядит FMX.TListBox при точно таких же настройках свойств:

Как видите, FMX.ListBox не делает никаких смещений элементов до тех пор пока не изменится значение Columns. Это мелочь, но такая, которая может в будущем при разработке программ очень пригодится.

Следующее известное нам по VCL свойство, заслуживающее внимания — это свойство Items.

Свойство Items

На первый взгляд может показаться, что работа с этим свойством в FMX.ListBox ничем не отличается от аналогичного свойства у VCL.ListBox. Действительно, мы можем найти в Object Inspector’е свойство Items:TStrings и вызвать знакомый редактор свойства:

Я не зря на скриншоте выше захватил также и окно Structure — обратите внимание на его содержимое. Помните, я говорил, что в Firemonkey каждый компонент — это контейнер для других компонентов? А в Structure никаких дочерних объектов у ListBox’а нет…а они где-то есть =) Получается, что я был не прав? Совсем нет.

Внимание! Фокус.

Сохраняем и закрываем проект. А затем снова открываем. И что мы видим? А вот такую интересную структуру проекта:

Вот Вам и четыре дочерних объекта для ListBox, да и ещё и без имени. Теперь, чтобы получить доступ к их свойствам нам придётся потратить какое-то количество времени и присвоить каждому из дочерних объектов имя и другие свойства. Чтобы не делать эту лишнюю работу, необходимо пользоваться «родным» редактором FMX.ListBox, который вызывается двойным щелчком мыши по компоненту. Выглядит редактор вот так:

В этом редакторе добавляются уже не строки (string), а непосредственно объекты типа TListBoxItem, которые и будут являться дочерними для нашего ListBox. Создаете в редакторе объект, редактируете его свойство Text в Object Inspector и все — никаких лишних движений по поводу изменения свойств вновь появившихся элементов.

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

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

Но, согласитесь, что в большинстве случаев, при работе с ListBox нам требуется заполнять свойство Items в run-time и тут нам редактор свойства не помощник. В run-time работать с ListBox можно также, как и в случае с VCL.ListBox, не опасаясь, что добавленная строка не будет восприниматься как объект TListBoxItem.

Вы можете записать новый элемент списка так:

begin
  MyListBox.Items.Add('Строка №1');
end;

и это сработает. И получить N-ый элемент списка так:

var S:string;
begin
  S:=MyListBox.Items[0]
end;

то и это тоже сработает. И в этом случае FMX.ListBox будет работать со своими дочерними объектами как со строками, т.е. при записи нового элемента принимать на входе строку и внутренними своими механизмами добавлять в список уже объект TListBoxItem, а при чтении, как показано выше, наоборот — брать элемент TListBoxItem и возвращать из него свойство Text. Проверить это можно довольно просто. Достаточно написать всего две строки кода:

  ListBox1.Items.Add('Строка');//записываем строку так как привыкли по VCL
  ShowMessage(ListBox1.ItemByIndex(0).ClassName);

Во второй строке я воспользовался методом ItemByIndex у FMX.ListBox, который возвращает объект типа TListBoxItem. Отдельный вопрос — как можно сортировать записи в ListBox, но это мы рассмотрим чуть попозже, а пока перейдем к другим свойствам.

Свойство ShowCheckboxes

Это свойство позволяет Вам использовать ListBox так же, как в VCL CheckBoxList, т.е. отображать рядом с каждой записью CheckBox. Включите это свойство и ListBox будет выглядеть так:

Теперь, чтобы обработать событие нажатия CheckBox’а нам достаточно обработать событие OnClickCheck у ListBox, например, таким образом:

procedure TForm8.ListBox1ChangeCheck(Sender: TObject);
begin
  if ListBox1.Selected.IsChecked then
    ShowMessage('Чекнули элемент '+ListBox1.Selected.Text)
end;

Свойство ListStyle

Это свойство определяет расположение элементов списка. Элементы списка TListBox в Firemonkey могу размещаться вертикально (ListStyle = lvVertical) также, как и в VCL, или горизонтально (ListStyle = lvVertical).

При горизонтальном расположении элементов списка свойство Columns будет определять не количество столбцов, а количество строк в списке. При этом каждый элемент списка, в зависимости от значения Columns будет стараться занять всё доступное ему место по вертикали и горизонтали. То есть список, представленный на рисунке выше, но имеющий свойство ListStyle = lsHorizontal и Columns = 1 будет выглядеть вот так:

Свойство AlternatingRowBackground

Свойство, позволяющее использовать альтернативный цвет для чётных элементов списка. Установите это свойство в значение True и получите вот такой красивый список:

Изменить альтернативный цвет строки можно немного подправив стиль оформления элементов формы, но к этому мы приступим ещё не скоро. Пока же можете запомнить, что этот цвет можно изменять.

Свойство ListItems

Это свойство, аналогично уже известному свойству Items для VCL.ListBox возвращает элемент списка по его индексу.

С другими свойствами компонента, которые относятся к свойствам, появившимся только в Firemonkey Вы можете ознакомиться в первой части серии постов «Firemonkey. От простого к сложному».

Перейдем теперь к методам компонента.

[adsenseyu1]

Метод SelectRange

procedure SelectRange(Item1, Item2: TListBoxItem);

Метод выделяет в списке элементы, начиная с Item1 и заканчивая Item2 включительно. Метод работает вне зависимости от того, какое значение имеет свойство MultiSelect:boolean.

Пример выделения первых четырех элементов списка:

ListBox1.SelectRange(ListBox1.ListItems[0],
                     ListBox1.ListItems[3]);

Методы ItemByPoint и ItemByIndex

function ItemByPoint(const X, Y: Single): TListBoxItem;
function ItemByIndex(const Idx: Integer): TListBoxItem;

Методы для получения элемента списка по координатам и индексу в списке. Получать объекты TListBoxItem из списка можно только, используя представленные выше методы, либо, используя свойство ListItems.

Методы AddObject, InsertObject, RemoveObject

  procedure AddObject(AObject: TFmxObject); override;
  procedure InsertObject(Index: Integer; AObject: TFmxObject); override;
  procedure RemoveObject(AObject: TFmxObject); override;

AddObject и InsertObject добавляют новый объект в конец или в заданную позицию списка. RemoveObject — удаляет заданный элемент из списка. В качестве входного параметра для методов может использоваться любой FMX-объект.

Метод Sort

procedure Sort(Compare: TFmxObjectSortCompare); override;

Этот метод позволяет нам сортировать элементы списка по своим собственным критериям. Для этого, в параметрах Sort необходимо передать компаратор, который имеет следующее описание:

  TFmxObjectSortCompare = function(item1, item2: TFmxObject): Integer;

Список можно отсортировать по значению строки, записанной в объекте TListBoxItem.

На сегодня закончим (тем более, что опять опубликовал пост раньше времени :( ) В следующий раз продолжим работу с компонентами списков и посмотрим как можно организовать взаимодействие между несколькими списками, используя LiveBindings.

Обсудить статью на форуме

0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
25 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Алексей
Алексей
18/11/2011 21:37

Думаю в статье все таки еще стоит упомянуть, что в текущей реализации списков, создание более 100 элементов чревато неимоверными тормозами. Так как поиск элемента по индексу приводит к полному перебору всех FMX объектов добавленных в список (даже если вы их не добавляли, через сравнение Item is TListBoxItem), и так как отрисовка, обработка нажатий клавиш, кликов и прочего использует ItemByIndex, то время реакции на пользовательский ввод растет в геометрической прогрессии от кол-ва добавленных элементов.

Алексей
Алексей
19/11/2011 00:04

Будем надеяться, что со временем все устаканится. Статьи понравились. С удовольствием почитаю продолжение.

mops
mops
21/11/2011 12:45

Так в XE2 есть поддержка Mac OS и iOS, и можно запускать приложения на маке (сам пробовал, получилось:), назрел такой вопрос: можно ли сделать приложение которое потом приняли бы в AppleStore? Там же какие-то сертификаты… Если знаете, расскажите. Спасибо.

mops
mops
21/11/2011 14:04

Скорее всего что-то с виртуалкой да, у меня без проблем все с первого раза заработало.

Алексей
Алексей
22/11/2011 00:50

Запостить в AppStore можно, только в начале нужно зарегистрироваться в программе MacOS Developer или IOS developer (в зависимости от того в какой сторе коммититить собираетесь), заплатить $100, отправить несколько документов. А уж потом в личном кабинете на сайте developer.apple.com будете получать сертификаты для постинга в сторе.

ParserYa
ParserYa
22/11/2011 23:14

Влад, очень интересные статьи ты пишешь.. Всегда приятно почитать. Тоже не давно начал разбираться с Firemonkey. Возник такой вопрос, может быть сможешь помочь.. Вообщем, ввиду задуманного интерфейса нужно мне в Firemonkey приложении использовать фреймы. Сами фреймы отсутсвуют — они VCL. Я пытался создавать дочернюю форму програмно, в качестве родителя(parent) указывая контрол на основной форме(TabControl) и потом вызывая Show(); для дочерней. С VCL-приложениями такая фишка работает, но Firemonkey все равно создает новую форму в виде модального окна. Сталкивался ли ты с реализацией фреймов в firemonkey? или может быть есть какие-то идеи, как это можно имитировать?

Алексей
Алексей
23/11/2011 13:37

ParserYA, у меня тоже есть приложения, которые используют TFrame. Пришлось поизучать исходники FMX, чтобы понять как можно сделать эквивалент. Пришел к такому временному варианту. Создал два файла uFrame.pas и uFrame.fmx.  (содержимое смотри ниже) Добавил их в проект.  А потом когда мне нужны были новые фрэймы, я просто делал так: правой кнопкой мыши кликал на проект->Add New->Other>Inhritable Items>Frame. И потом работал как с обычным TFrame. Правда создавал фрэймы только в Runtime. К сожалению пока не было времени понять, как его зарегистрировать в виде компонента на палитре. Если у кого-нибудь получится — буду премного благодарен. ————- uFrame.pas———————- [code] unit uFrame; interface uses… Подробнее »

ParserYa
ParserYa
23/11/2011 23:38

Влад, я смотрел эти компоненты — это не совсем то.. Даже если заглянуть в исходники видно, что это простые скролл-боксы.. Может быть, изначально у них и задумывалось им что-то особенное сделать, но потом видимо передумали. Алексей, я вчера полез на форум Embarcadero и там наткнулся на интересные фишки(хотя по сути костыли). Метод заключается в том, что бы положить на форму-псеводфрейм(frame1:TForm1) глобальный блок(Layout1). А в нашей основной форме(fmMain) скопировать объект в какой-то контейнер(LayFrameContainer:TLayout): [code] var f1: Tform1; begin   f1 := TForm1.Create(Self);   LayFrameContainer.AddObject(F.Layout1); end; [/code]  Таким образом, мы не привязываемся не к каким дополнительным классам. Создаем интерфейс/пишем весь код связанный с… Подробнее »

ter
ter
30/11/2011 13:59

Странно что SelectRange работает с объектами а не индексами. Ну или по крайней мере не имеет перегруженной версии для работы с индексами.
также странно что компаратор для объектов это указатель на функцию, а не анонимный метод, каким он обычно представляется, в частности в дженериках.
 
зы: про фреймы — в следующем (19й английский) выпуск Blaise Pascel Magazine статья будет про фреймы, там правда тоже костыли, которые не особо мне понравились (:

ParserYa
ParserYa
02/12/2011 17:22

Подскажите, а что в FireMonkey у форм нет параметров «Минимальная ширина» и «Минимальная высота»? Это только динамически, через onResize что ли отлавливать?

Алексей
Алексей
02/12/2011 19:04

ParseYA: Похоже на то. Я другого не нашел.

юра
юра
08/12/2011 15:41

не пойму. не могу динамически поменять

юра
юра
08/12/2011 15:42

не могу поменять динамически курсор

Bogdan
Bogdan
13/12/2011 20:10

Хорошая статья, автору респект, тоже потихоньку перевожу свои проекты на FireMonkey, занял первое место на конференции благодаря ему) , но возникли небольшие вопросы в связи с этим.. В частности: как в FireMonkey e-mail отправить? Что-то у меня не выходит.. Автору просьба, может написать статью с примерами кроссплатформенного программирования..Отправки тогоже e-mail к примеру.. Думаю не одному мне  это будет интересно..)

Bogdan
Bogdan
14/12/2011 00:31

Насколько я понял в XE2 у TidSMTP сменились некоторые свойства.. а разбираться с ними нет времени.. Всёж ещё и учиться надо.. Вообщем, можно небольшой пример, плз, а то как раньше было не прокатывает.. А то не хочется по ошибке выдавать сообщение «Отправте инфу на e-mail», хочется самому отправить… Как раньше было, блин.

trackback

[…] и в случае с TListBox, в случае, если это свойство равно True каждая вторая […]

KingComp
08/05/2012 12:08

Пытался создать нечто вроде ListView (с динамическим количеством SubItems). Для этого взял ListBox1 зашел в Edit Custom Style. В редакторе стиля сделал следующее: в наш ListBox1 засунул ListBox2 и в ListBox2 поменял свойства ListStyle = lsHorizontal, а Align = alTop. Вроде бы все здорово. Можно в ListBox2 добавлять Items, которая будет играть роль SubItems для ListBox1. Но как получить доступ к Items для ListBox2? Это поле пропадает для ListBox2, к нему есть доступ только в EditCustomStyle. Может кто сможет решить эту задачу?!

Pavel Alhymov
Pavel Alhymov
29/01/2013 22:38

Жаль, что у ListItems нет нумератора — нельзя foreach использовать. А хотелось бы.

trackback

[…] В FireMonkey все по-другому — по другому организована работа с компонентами, по другому работают стили, по другому реализован […]

Алексей
Алексей
09/04/2016 23:47

Почему-то не работает такая строчка:
for I := 0 to ListBox1.Count-1 do
ListBox1.ItemByIndex(i).TextSettings.HorzAlign:= TTextAlign.Center;

Все элементы всё равно имеют левый алигн.