Шаблон списка объектов, класс TObjectListo

Рассмотрим очередной шаблонный класс, входящий в состав модуля System.Generics.Collections. Класс TObjectListo легко справится с хранением лю­бого заданного программистом перечня объектов и предоставит доступ к любому из объектов по его индексу.
По своей сути класс представляет собой список, способный выступать владельцем объектов. Именно поэтому, при создании экземпляра класса конструктор
constructor Create(AOwnsObjects: Boolean = True);
по умолчанию устанавливает аргумент владения AOwnsObjects в состояние true. Впрочем, если по какой-то причине в момент создания списка вы передали в конструктор аргумент false, никто не запретит вам передумать и сделать список вла­дельцем объектов. Для этого обратитесь к свойству
property OwnsObjects: Boolean; из кода вашей программы.

Среди примеров к книге есть небольшая программа-игра, демонстрирующая работу TObjectListo. Суть игры заключается в том, что пользователь должен ловить ле­тящие вниз шарики — экземпляры класса TCircie

Шаблон списка объектов, класс TObjectListo
Не трудно догадаться, что главная роль в коде отводится списку TObjectListo, ко­торый возьмет на себя обязанности по обслуживанию падающих с "небес" объек­тов. Работа приложения начинается с создания списка

 

 
 
 
var Forml: TForm;
List: TObjectList<TCircle>; //список объектов TCircieimplementation
{$R *.fmx}
procedure TForml.FormCreate(Sender: TObj ect); begin
List:=TObjectList<TCircle>.Create;//здесь будут храниться шарики end;
 
 
 

Как видите, в момент объявления объектной переменной List: TObjectList<TCircie> мы явным образом указываем, что список намерен дружить исключительно с ша­риками TCircie.

В программе задействованы два таймера. Первый из них, компонент Timeri, отве­чает за создание очередной порции шариков, это происходит каждый раз, как у таймера генерируется событие отсчета времени
 
 
procedure TForml.TimerlTimer(Sender: TObject);
var Circle:TCircle;
begin
Randomize;
Circle:=TCircle.Create(nil); //очередной шарик
List.Add(Circle); //добавляем шарик в список
Circle.Parent:= Forml;
Circle.Position,Y:=0;//место появления шарика на форме Circle.Position.X:=Random(Round(Forml.ClientWidth-Circle.Width));end;

 

В коде программы для добавления очередного объекта к списку задействуется метод

function Add(const Value: T): Integer;

Однако это не единственный способ пополнения списка, кроме метода Add (), до­бавляющего объект самым последним в список, в арсенале класса TObjectList<T>имеется метод

procedure Insert(Index: Integer; const Value: T);

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

Кроме того, у класса предусмотрен целый ряд перегружаемых методов procedure AddRange(const Values: array of T);

procedure InsertRange(Index: Integer; const Values: array of T); умеющих за один присест добавить/вставить целую партию объект

ов.

Возвращаемся к нашей программе, а точнее, ко второму таймеру Timer2. В круг обязанностей этого компонента входит:

  •  управление процессом постепенного опускания шариков от места их создания (верхней грани формы) вниз формы, где их попытается поймать пользователь;
  • удаление пойманных и пропущенных шариков.

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

property Count: Integer;

и передать индекс интересующего нас элемента в свойство

property Items[Index: Integer]: T;

Пойманным считается шарик, попавший на поверхность биты, реализованной на основе компонента TRectangie, пропущенным — шарик, пролетевший мимо 

 

	procedure TForml.Timer2Timer(Sender: TObj ect);
var i:integer;
begin
for i :=0 to List.Count-1 do //перебираем все объекты with List.Items[i] do begin
Position.Y:=Position.Y+0.5;//опускаем шарик вниз //проверяем, не попал ли шарик на биту Rectanglel:TRectangieif (Position.Y+Height>=Rectanglel.Position.Y)and (Position.X>=Rectanglel.Position.X)and
(Position.X<=Rectanglel.Position.X+Rectanglel.Width)thenbegin
//элемент пойман List.Delete(i); //удаляем шарик//... подсчет пойманных шариков Break; //прерываемцикл
end else
if (Position.Y+Height>=Rectanglel.Position.Y) then begin //элемент не пойман List.Delete(i);//удаляем шарик //... подсчет пропущенных шариков Break; //прерываем цикл
end;
end; 
end;
 

 

Замечание: В Delphi ХЕ5 конструкция with, .do вполне приемлема, однако, возможно, очень скоро ее перестанут рекомендовать к использованию. Причина такого предположения в том, что with, .do изначально проектировалась для устаревших объектов 

В любом случае пойманный или пропущенный шарик подлежит удалению. Для этого мы воспользовались методом

procedure Delete(Index: Integer);

Важно запомнить, что если список является владельцем объектов, то вызов метода Delete (), во-первых, уничтожит объект, а во-вторых, упакует список (удалит осво­бодившиеся ячейки и уменьшит значение count).

Если бы логика программы предполагала не уничтожение объекта, а лишь изъятие его из списка, то лучше было бы воспользоваться методом

function Extract(const Value: T): T;

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

На этом функционал списка TObjectList<T> далеко не заканчивается. Класс- шаблон способен еще на многое. В частности, он умеет перемещать элемент из по­зиции Curlndex В ПОЗИЦИЮ Newlndex С ПОМОЩЬЮ процедуры

procedure Move(Curlndex, Newlndex:Integer);

Чтобы поменять элементы местами, обращаемся к методу

procedure Exchange(Indexl, Index2:Integer);

Сортировка объектов в списке производится методами

 

	procedure Sort; overload;
	procedure Sort(const AComparer:IComparer<T>); overload;

 

При желании весь список может быть представлен в формате массива-шаблона

function ToArray: TArray<T>;

И наконец, список обладает событием

 

	property OnNotify:TCollectionNotifyEvent<T>;
	TCollectionNotifyEvent<T>= procedure(Sender: TObject;
	const Item: T; Action: TCollectionNotification) of object;

генерирующимся в момент пополнения списка новым объектом или удаления объ­екта из списка. О характере события сигнализирует параметр Action, принимая зна­чения cnAdded, cnRemoved ИЛИ cnExtracted.

 

 

 

dle

Помоги проекту! Расскажи друзьям об этом сайте: