Списки и коллекции


Практически любое приложение должно уметь выполнять ряд стандартных операций по обработке каких-либо данных. К ним относятся загрузка данных при открытии приложения, представление данных в удобном виде для использования внутри приложения, сохранение данных при завершении работы. Перечисленные действия необходимы и приложениям баз данных, и играм, и научным программам.
В принципе хранение и использование наборов значений можно обеспечить при помощи хорошо всем известных массивов. Однако их прямое использование требует от разработчика дополнительных усилий. Ведь при реализации программной логики необходимо добавлять в массив новые элементы, изменять существующие и удалять ненужные. Кроме этого, часто бывает необходимо найти элемент массива по значению. Все эти операции стандартны и повторяются для наборов любых типов данных.
Для решения перечисленных задач в Delphi доступны для использования специальные классы. Помимо хранения наборов значений в них реализованы свойства, позволяющие контролировать состояние списка и методы, обеспечивающие редактирование списка и поиск в нем отдельных элементов.
Для загрузки и сохранения данных используются потоки — классы, инкапсулирующие механизмы доступа к различным хранилищам информации — файлам, памяти и т. д. Их общим предком является класс Tstream.
Для работы со строковыми списками предназначены классы TStrings и TStringList.
Любые типы данных можно заносить в список указателей, который реализован в классе TList.
Использование наборов объектов (широко применяются в классах VCL), которые называются коллекциями, осуществляется при помощи классов TCollection И TCollectionltem.
В этой главе рассматриваются следующие вопросы:

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

Список строк


Строковый тип данных широко используется программистами. Во-первых, многие данные действительно необходимо представлять при помощи этого типа. Во-вторых, множество функций преобразования типов позволяют представлять числовые типы в виде строк, избегая тем самым проблем с несовместимостью типов.
По этой причине в первую очередь мы займемся изучением списка строк, который инкапсулирован в классах TStrings и TStringList. Первый класс является абстрактным и служит платформой для создания реально работающих потомков. Второй класс реализует вполне работоспособный список строк. Рассмотрим эти классы подробнее
Класс TStrings
Класс TStrings является базовым классом, который обеспечивает потомков основными свойствами и методами, позволяющими создавать работоспособные списки строк. Его прямым предком является класс TPersistent.
Класс TStrings реализует все вспомогательные свойства и методы, которые обеспечивают управление списком. При этом методы, непосредственно добавляющие и удаляющие элементы списка, не реализованы и объявлены как абстрактные.
Внимание
Попытка прямого использования в приложении экземпляра класса TStrings вызовет ошибку применения абстрактного класса на этапе выполнения программы, а именно при попытке заполнить список значениями. Простая замена типа объектной переменной списка на TStringList делает приложение полностью работоспособным без какого-либо дополнительного изменения исходного кода.
Классы-наследники должны перекрывать методы добавления и удаления элементов списка. Реализованный в Delphi класс TStringList практически полностью повторяет функциональность предка, добавляя лишь несколько новых свойств и методов. Поэтому мы не станем останавливаться подробнее на классе TStrings, а перейдем сразу к его работоспособному потомку TStringList.
 
Класс TStringList
Класс TStringList обеспечивает реальное использование списков строк в приложении. По существу, класс представляет собой оболочку вокруг динамического массива значений списка, представленного свойством strings. Объявление свойства (унаследованное от TStrings) выглядит так:
property Strings[Index: Integer]: string read Get write Put; default;
Для работы со свойством используются внутренние методы Get и Put, в которых применяется внутренняя переменная FList:
type
PStringltem = 'TStringltem;
 TStringltem = record FString: string; 
FObject: TObject;
  end;
PStringltemList = ^TStringItemList; 
TStringltemList = array[0..MaxListSize] of TStringltem;
FList: PStringltemList;
Из ее объявления видно, что список строк представляет собой динамический массив записей TStringItem. Эта запись позволяет объединить саму строку и связанный с ней объект.
Максимальный размер списка ограничен константой
MaxListSize = Maxint div 16;
значение которой после нехитрых вычислений составит 134 217 727. Таким образом, видно, что строковый список Delphi теоретически конечен, хотя на практике гораздо чаще размер списка ограничивается размером доступной памяти.
Обращение к отдельному элементу списка может осуществляться через свойство strings таким образом:
SomeStrings.Strings[i] := Editl.Text;
или так:
SomeStrings[i] := Editl.Text;
Оба способа равноценны.
При помощи простого присваивания можно задавать новые значения только тогда, когда элемент уже создан. Для добавления нового элемента используются методы Add И AddStrings.
Функция
function Add(const S: string): Integer;
добавляет в конец списка новый элемент, присваивая ему значение s и возвращая индекс нового элемента в списке.
Метод
procedure Append(const S: string);
просто вызывает функцию Add. Единственное отличие заключается в том, что метод не возвращает индекс нового элемента.
Метод
procedure AddStrings(Strings: TStrings);
добавляет к списку целый набор новых элементов, которые должны быть заданы другим списком, передаваемым в параметре strings.
При необходимости можно добавить новый элемент в произвольное место списка. Для этого применяется метод
procedure Insert(Index: Integer; const S: string);
который вставляет элемент s на место элемента с индексом index. При этом все указанные элементы смещаются на одну позицию вниз.
Для удаления элемента списка используется метод
procedure Delete(Index: Integer);
Метод
procedure Move(Curlndex, Newlndex: Integer);
перемещает элемент, заданный индексом curindex, на новую позицию, заданную индексом Newlndex.
А метод
procedure Exchange(Indexl, Index2: Integer);
меняет местами элементы с индексами index1 и index2.
Довольно часто в списках размешается строковая информация следующего вида:
'Name=Value'
В качестве примера можно привести строки из файлов INI или системного реестра. Специально для таких случаев в списке предусмотрено представление строк в двух свойствах. В свойстве Names содержится текст до знака равенства. В свойстве values содержится текст после знака равенства по умолчанию. Однако символ-разделитель можно заменить на любой другой, использовав свойство
property NameValueSeparator: Char;
Доступ к значениям свойства values осуществляется по значению. Например, если в списке есть строка
City=Saint-Petersburg
то значение свойства value будет равно
Value['City'] = 'Saint-Petersburg'
Кроме этого, значение свойства value можно получить, если известен его индекс:
property ValueFormlndex[Index: Integer]: string;
Как видно из объявления внутреннего списка FList (см. выше), с каждым элементом списка можно связать любой объект. Для этого используется свойство
property Objects[Index: Integer]: TObject;
Свойство strings элемента и свойство objects связанного с ним объекта имеют одинаковые индексы. Если строка не имеет связанного объекта, то свойство objects равно Nil. Один объект может быть связан с несколькими строками списка одновременно.
Чаще всего объекты нужны для того, чтобы хранить для каждого элемента дополнительную информацию. Например, в списке городов для каждого элемента можно дополнительно хранить население, площадь, административный статус и т. д. Для этого можно создать примерно такой класс:
TCityProps = class(TObject)
  Square: Longlnt;
  Population: Longlnt; 
Status: String/end;
Для того чтобы добавить к строке из списка объект, используется метод AddObject:
function AddObject(const S: string; AObject: TObject): Integer; virtual;
Обратите внимание, что в параметре AObject необходимо передавать указатель на объект. Проще всего это сделать таким образом:
SomeStrings.AddObject('Someltem', TCityProps.Create);
Или же так:
var SPb: TCityProps;
...
SPb := TCityProps.Create; {Создание объекта}
 SPb.Population := 5000000;
...
SomeStrings.Strings[i] := 'Санкт-Петербург';
SomeStrings.Objects[i] := SPb; (Связывание объекта и строки}
Можно поступить и подобным образом (помните, что строка уже должна существовать):
...
SomeStrings.Strings[i] := 'Санкт-Петербург';
  SomeStrings.Objects[i] := TCityProps.Create;
(SomeStrings.Objects[i] as TCityProps).Population := 5000000;
...
Аналогично методу insert, элемент и связанный с ним объект можно вставить в произвольное место списка методом
procedure InsertObject(Index: Integer; const S: string; AObject: TObject);
При перемещении методом Move вместе с элементом переносится и указатель на связанный объект.
Обратите внимание на две особенности, связанные с удалением указателей на объекты и самих связанных объектов.
При удалении элемента списка удаляется только указатель на объект, а сам объект остается в памяти. Для его уничтожения следует предпринять дополнительные усилия:
...
for i := 0 to SomeList.Count — 1 do 
SomeList.Objects[i].Destroy;
...
Если при удалении связанного объекта необходимо выполнить некоторые действия, предусмотренные в деструкторе, приведение типов
TCityProps(SomeList.Objects[i]).Destroy;
выполнять не обязательно — нужный деструктор будет вызван автоматически, хотя в данном случае приведение типов ошибкой не является.
Метод
procedure Clear; override;
полностью очищает список, удаляя все его элементы.
Помимо перечисленных, класс TStringList обладает рядом дополнительных свойств и методов. Вспомогательные свойства класса обеспечивают разработчика информацией о состоянии списка. Дополнительные методы осуществляют поиск в списке и взаимодействие с файлами и потоками.
Свойство только для чтения
property Count: Integer;
возвращает число элементов списка.
Так как основу списка составляет динамический массив, то для него в процессе работы должна выделяться память. При добавлении в список новой строки память для нее выделяется автоматически. Свойство
property Capacity: Integer;
определяет число строк, для которых выделена память. Вы можете самостоятельно управлять этим параметром, помня при этом, что значение Capacity всегда должно быть больше или равно значению Count.
Свойство
property Duplicates: TDuplicates;
определяет, можно ли добавлять в список повторные значения. 
Тип
type
TDuplicates = (duplgnore, dupAccept, dupError);
определяет реакцию списка на добавление повторного элемента: 

  •  dupignore —- запрещает добавление повторных элементов;
  •   dupAccept — разрешает добавление повторных элементов;
  •  dupError — запрещает добавление повторных элементов и генерирует исключительную ситуацию.

Класс TStringList немыслимо представить себе без возможностей сортировки. Если вас удовлетворит обычная сортировка, то для этого можно использовать свойство sorted (сортировка выполняется при значении True) или метод Sort. Под "обычной" имеется в виду сортировка по тексту строк с использованием функции Ansicomparestr (т. е. с учетом национальных символов, в порядке возрастания). Если вы хотите отсортировать список по другому критерию, к вашим услугам метод:
type
TStringListSortCompare = function(List: TStringList; Indexl, Index2: Integer): Integer;
 procedure CustomSort(Compare: TStringListSortCompare);
Чтобы отсортировать список, вы должны описать функцию сравнения двух элементов с индексами indexl и index2, которая должна возвращать следующие результаты:

  •  1 — если элемент с индексом indexl вы хотите поместить впереди элемента Index2;
  • 0 — если они равны;
  •  1 — если элемент с индексом indexl вы хотите поместить после элемента Index2.

Для описанного выше примера с объектом-городом нужны три процедуры:
function SortByStatus(List: TStringList; Indexl, Index2: Integer):
Integer;
begin
Result := AnsiCompareStr((List.Objects[Indexl] as TCityProps).Status,
(List.Objects[Index2] as TCityProps).Status; 
end;
function SortBySquare(List: TStringList; Indexl, Index2: Integer): Integer; 
begin if (List.Objects[Indexl] as TCityProps).Square <
(List.Objects[Index2] as TCityProps). Square) then Result := -1
 else if (List.Objects[Indexl] as TCityProps).Square =
(List.Objects[Index2] as TCityProps).Square then Result := 0
 else Result := 1;
  end;
function SortByPopulation(List: TStringList; Indexl, Ir.dex2: Integer): Integer; 
begin
if (List.Objects[Indexl] as TCityProps).Population < (List.Objects[Index2] as TCityProps). Population then Result := -1 
else
if (List.Objects[Indexl] as TCityProps). Population = (List.Objects[Index2] as TCityProps). Population
 then Result := 0
 else Result := 1; 
end;
Передаем одну из процедур в метод CustomSort:
Cities.CustomSort(SortByPopulation);
Для поиска нужного элемента используется метод
function Find(const S: string; var Index: Integer): Boolean;
В параметре s передается значение для поиска. В случае успеха функция возвращает значение True, а в параметре index содержится индекс найденного элемента.
Метод
function IndexOf (const S: string): Integer;
возвращает индекс найденного элемента s. Иначе функция возвращает — 1. 
Метод
function IndexOfName(const Name: string): Integer;
возвращает индекс найденного элемента, для которого свойство Names совпадает со значением параметра Name.
Для поиска связанных объектов используется метод
function IndexOfObject(AObject: TObject): Integer;
В качестве параметра AObject должна передаваться ссылка на искомый объект. А свойство
property CaseSensitive: Boolean;
включает или отключает режим поиска и сортировки с учетом регистра символов.
Помимо свойства strings, содержимое списка можно получить при помощи свойств
property Text: string;
И
property CommaText: string;
Они представляют все строки списка в виде одной строки. При этом в первом свойстве элементы списка разделены символами возврата каретки и переноса строки. Во втором свойстве строки заключены в двойные кавычки и разделены запятыми или пробелами. Так, для списка городов (Москва, Петербург, Одесса) свойство Text будет равно
Москва#$0#$АПетербург#$0#$АОдесса
а свойство CommaText равно
"Москва", "Петербург", "Одесса".
Важно иметь в виду, что эти свойства доступны не только по чтению, но и по записи. Так что заполнить список вы сможете не только циклически, вызывая и используя методы Add или insert, но и одним-единственным присвоением значения свойствам Text или CommaText.
Список может взаимодействовать с другими экземплярами класса TstringList. 
Широко распространенный метод
 procedure Assign(Source: TPersistent);
 полностью переносит список source в данный. 
Метод
function Equals(Strings: TStrings): Boolean;
возвращает значение True, если элементы списка strings полностью совпадают с элементами данного списка.
Список можно загрузить из файла или потока. Для этого используются методы
procedure LoadFromFile(const FileName: string);
И
procedure LoadFromStream(Stream: TStream);
Сохранение списка выполняется методами
procedure SaveToFile(const FileName: string);
И
procedure SaveToStreamfStream: TStream);
Перед изменением списка вы можете получить управление, описав обработчик события
property OnChange: TNotifyEvent;
а после изменения
property OnChanging: TNotifyEvent;
На дискете, прилагаемой к этой книге, вы можете ознакомиться с примером использования списков строк DemoStrings.
 
Список указателей

Для хранения списка указателей на размещенные в адресном пространстве структуры (объекты, динамические массивы, переменные) предназначен класс TList. Так же, как и список строк TstringList, список указателей обеспечивает эффективную работу с элементами списка.
Класс TList
Основой класса TList является список указателей. Сам список представляет собой динамический массив указателей, к которому можно обратиться через индексированное свойство
property Items[Index: Integer]: Pointer;
Нумерация элементов начинается с нуля.
Прямой доступ к элементам массива возможен через свойство
type
PPointerList = ^TPointerList;
TPointerList = array[0..MaxListSize-1] of Pointer;
 property List: PPointerList;
которое имеет атрибут "только для чтения".
Так как элементы списка являются указателями на некоторые структуры, прямое обращение к составным частям этих структур через свойство items невозможно. Как это можно сделать, рассказывается ниже в примере.
 Примечание
В списке могут содержаться указатели на разнородные структуры. Не обязательно хранить в списке только указатели на объекты или указатели на записи.
Реализованные в классе TList операции со списком обеспечивают потребности разработчика и совпадают с операциями списка строк.
Для добавления в конец списка нового указателя используется метод
function Add(Item: Pointer): Integer;
Прямое присваивание значения элементу, который еще не создан при помощи метода Add, вызовет ошибку времени выполнения.
Новый указатель можно добавить в нужное место списка. Для этого используется метод
procedure Insert(Index: Integer; Item: Pointer);
В параметре index указывается необходимый порядковый номер в списке.
Перенос существующего элемента на новое места осуществляется методом
procedure Move(Curlndex, Newlndex: Integer);
Параметр CurIndex определяет старое положение указателя. Параметр NewIndex задает новое его положение.
Также можно поменять местами два элемента, определяемые параметрами Indexl и Index2:
procedure Exchange(Indexl, Index2: Integer);
Для удаления указателей из списка используются два метода. Если известен индекс, применяется метод
procedure Delete(Index: Integer);
Если известен сам указатель, используется метод
function Remove(Item: Pointer): Integer;
Эти методы не уменьшают объем памяти, выделенной под список. При необходимости сделать это следует использовать свойство capacity. Также существует метод Expand, который увеличивает отведенную память автоматически в зависимости от текущего размера списка.
function Expand: TList;
Для того чтобы метод сработал, необходимо, чтобы count = Capacity. Алгоритм работы метода представлен в табл. 7.1.
Таблица 7.1. Алгоритм увеличения памяти списка


Значение свойства Capacity

На сколько увеличится свойство Capacity

<4

4

4..8

8

>8

16

Метод
procedure Clear; dynamic;
используется для удаления всех элементов списка сразу. Для поиска указателя по его значению используется метод
function IndexOf(Item: Pointer): Integer;
Метод возвращает индекс найденного элемента в списке. При неудачном поиске возвращается — 1.
Для сортировки элементов списка применяется метод
type TListSortCompare = function (Iteml, Item2: Pointer): Integer;
 procedure Sort(Compare: TListSortCompare);
Так как состав структуры, на которую указывает элемент списка, невозможно заранее обобщить, разработка процедуры, осуществляющей сортировку, возлагается на программиста. Метод Sort лишь обеспечивает попарное сравнение указателей на основе созданного программистом алгоритма (пример сортировки см. выше в разд. "Класс TStringList").
Полностью все свойства и методы класса TList представлены в табл. 7.2.
Таблица 7.2. Свойства и методы класса TList


Объявление

Описание

property Capacity: Integer;

Определяет число строк, для которых выделена память

property Count: Integer;

Возвращает число строк в списке

property Items [Index: Integer]: Pointer;

Список указателей

type
TPointerList = array [0 . .MaxListSize-i ] of Pointer;
PPointerList = ATPointerList; property List: PPointerList;

Динамический массив указателей

function Add (Item: Pointer): Integer;

Добавляет к списку новый указатель

procedure Clear; dynamic;

Полностью очищает список

procedure Delete (Index: Integer:;

Удаляет указатель с индексом
Index

class procedure Error (const Ksg: string; Data: Integer); virtual;

Генерирует исключительную
Ситуацию EListError.
Сообщение об ошибке создается из форматирующей строки Msg и числового параметра Data

procedure Exchange (Indexl, Index2: Integer);

Меняет местами указатели с индексами Indexl и Index2

function Expand: TList;

Увеличивает размер памяти, отведенной под список

function First: Pointer;

Возвращает первый указатель из списка

function IndexOf (Item: Pointer): Integer;

Возвращает индекс указателя, заданного параметром Item

procedure Insert (Index: Integer; Item: Pointer) ;

Вставляет новый элемент Items позицию Index

function Last: Pointer;

Возвращает последний указатель в списке

procedure Move (Curlndex, Newlndex: Integer);

Перемещает элемент списка на новое место

procedure Pack;

Удаляет из списка все пустые (Nil) указатели

function Remove (Item: Pointer): Integer;

Удаляет из списка указатель
Item

type TListSortCompare = function (Iteml, Item2 : Pointer): Integer;
procedure Sort (Compare: TListSortCompare);

Сортирует элементы списка

 
Пример использования списка указателей
Рассмотрим использование списков указателей на примере приложения DemoList. При щелчке мышью на форме приложения отображается точка, которой присваивается порядковый номер. Одновременно координаты и номер точки записываются в соответствующие свойства создаваемого экземпляра класса TMypixel. Указатель на этот объект передается в новый элемент списка pixList.
В результате после очистки формы всю последовательность точек можно восстановить, использовав указатели на объекты точек из списка.
Список точек можно отсортировать по координате X в порядке возрастания.
Листинг 7.1. Модуль главной формы проекта DemoList
unit Main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, 
Dialogs, StdCtrls, Buttons;
type
TMainForm = class(TForm) 
ListBtn: TBitBtn;
  ClearBtn: TBitBtn; 
DelBtn: TBitBtn;
  SortBtn: TBitBtn;
procedure FormCreate(Sender: TObject); 
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
procedure ListBtnClick(Sender: TObject);
procedure ClearBtnClick(Sender: TObject);
procedure DelBtnClick(Sender: TObject);
procedure SortBtnClick(Sender: TObject); 
private
PixList: TList;
PixNum: Integer; public
{ Public declarations } 
end;
TMyPixel = class(TObject)
FX: Integer;
FY: Integer;
FText: Integer;
constructor Create(X, Y, Num: Integer);
procedure SetPixel; 
end;
var
MainForm: TMainForm;
implementation
{$R *.DFM}
const PixColor = clRed;
var CurPixel: TMyPixel;
constructor TMyPixel.Create(X, Y, Num: Integer); 
begin
inherited Create;
FX := X;
FY := Y;
FText := Num;
SetPixel;
  end;
procedure TMyPixel.SetPixel; 
begin
MainForm.Canvas.PolyLine([Point(FX, FY), Point(FX, FY)]);
MainForm.Canvas.TextOut(FX +1, FY + 1, IntToStr(FText)); 
end;
function PixCompare(Iteml, Item2: Pointer): Integer;
var Pixl, Pix2: TMyPixel;
begin
Pixl := Iteml;
Pix2 := Item2;
Result := Pixl.FX — Pix2.FX;
  end;
procedure TMainForm.FormCreate(Sender: TObject);
 begin
PixList := TList.Create;
PixNum := 1; {Счетчик точек}
Canvas.Pen.Color := PixColor; (Цвет точки}
Canvas.Pen.Width := 3; {Размер точки}
Canvas.Brush.Color := Color; (Цвет фона текста равен цвету формы}
 end;
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
 begin
PixList.Free;
  end;
procedure TMainForm.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); 
begin
PixList.Add(TMyPixel.Create(X, Y, PixNum));
Inc(PixNum); 
end;
procedure TMainForm.ListBtnClick(Sender: TObject);
var i: Integer;
begin
with PixList do
for i := 0 to Count — 1 do
begin
CurPixel := Items[i]; CurPixel.SetPixel;
end; end;
procedure TMainForm.ClearBtnClick(Sender: TObject);
 begin
Canvas.FillRect(Rect(0, 0, Width, Height));
  end;
procedure TMainForm.DelBtnClick(Sender: TObject); 
begin
PixList.Clear;
PixNum := 1;
  end;
procedure TMainForm.SortBtnClick(Sender: TObject);
var i: Integer;
begin
PixList.Sort(PixCompare);
with PixList do
for i := 0 to Count — 1 do TMyPixel(Items[i]).FText := i + 1; 
end;
end.
Класс TMyPixel обеспечивает хранение координат точки и ее порядковый номер в серии. Эти параметры передаются в конструктор класса. Метод setPixel обеспечивает отрисовку точки на канве формы (см. гл. 10).
Экземпляр класса создается для каждой новой точки при щелчке кнопкой мыши в методе-обработчике FormMouseDown. Здесь же указатель на новый объект сохраняется в создаваемом при помощи метода Add элементе списка PixList. Таким образом, программа "запоминает" расположение и порядок следования точек.
Метод-обработчик ListBtnClick обеспечивает отображение точек. Для этого в цикле текущий указатель списка передается в переменную объектного типа curPixel, т. е. в этой переменной по очереди "побывают" все созданные объекты, указатели на которые хранятся в списке.
Это сделано для того, чтобы получить доступ к свойствам объектов (непосредственно через указатель этого сделать нельзя). Второй способ приведения типа рассмотрен в методе-обработчике SortBtnClick.
Перед вторичным отображением точек необходимо очистить поверхность формы. Эту операцию выполняет метод-обработчик clearBtnClick.
Список точек можно отсортировать по координате X в порядке возрастания. Для этого в методе-обработчике SortBtnClick вызывается метод Sort списка PixList. В параметре метода (переменная процедурного типа) передается функция PixCompare, которая обеспечивает инкапсулированный в методе Sort механизм перебора элементов списка алгоритмом принятия решения о старшинстве двух соседних элементов.
Если функция возвращает положительное число, то элемент item1 больше элемента item2. Если результат отрицательный, то item1 меньше, чем item2. Если элементы равны, функция должна возвращать ноль.
В нашем случае сравнивались координаты X двух точек. В результате такой сортировки по возрастанию объекты оказались расположены так, что первый элемент списка указывает на объект с минимальной координатой X, а последний — на объект с максимальной координатой X.
После сортировки осталось заново пронумеровать все точки. Это делает цикл в методе-обработчике SortBtnclick. Обратите внимание на примененный в этом случае способ приведения типа, обеспечивающий обращение к свойствам экземпляров класса TMypixel.
Метод-обработчик DeiBtnClick обеспечивает полную очистку списка pixList.
 
Коллекции
Коллекция представляет собой разновидность списка указателей, оптимизированную для работы с объектами определенного вида. Сама коллекция инкапсулирована в классе Tсоllection. Элемент коллекции должен быть экземпляром класса, унаследованного от класса TCollectionitem. Это облегчает программирование и позволяет обращаться к свойствам и методам объектов напрямую.
Коллекции объектов широко используются в компонентах VCL. Например, панели компонента TCoolBar (см. гл. 5) объединены в коллекцию. Класс TCooiBands, объединяющий панели, является наследником класса TCollection. А отдельная панель — экземпляром класса TCoolBar, происходящего от класса TCollectionitem.
Поэтому знание свойств и методов классов коллекции позволит успешно использовать их при работе со многими компонентами (TDBGrid, TListview, TStatusBar, TCoolBar и т. д.).
Для работы с коллекцией, независимо от инкапсулирующего ее компонента, применяется специализированный Редактор коллекции (1), набор элементов управления которого может немного изменяться для разных компонентов.
Список Редактора объединяет элементы коллекции. При выборе одной строки из списка свойства объекта коллекции становятся доступны в Инспекторе объектов. В список можно добавлять новые элементы и удалять существующие, а также менять их взаимное положение.
Примеры использования коллекций представлены при описании соответствующих компонентов.
 
Класс TCollection
Класс TCollection является оболочкой коллекции, обеспечивая разработчика набором свойств и методов для управления ею (табл. 7.3).
Сама коллекция содержится в свойстве
property Items[Index: Integer]: TCollectionltem;
Полное объявление свойства в классе выглядит следующим образом:
property Items[Index: Integer]: TCollectionltem read Getltem write Setltem;
Методы Getitem и Setltem обращаются к внутреннему полю Fitems:
FItems: TList;
Именно оно хранит коллекцию объектов во время выполнения. Отсюда следует, что коллекция представляет собой список указателей на экземпляры класса TCollectionltem или его наследника. Класс TCollection обеспечивает удобство использования элементов списка.
Таблица 7.3. Свойства и методы класса TCollection


Объявление

Описание

property Count: Integer;

Возвращает число элементов коллекции

type TcollectionltemClass = class of Tcollectionltem;
property ItemClass: TcollectionltemClass;

Возвращает класс-наследник
TCollectionltem, экземпляры которого собраны в коллекции

property Items [Index: Integer]: Tcollectionltem;

Коллекция экземпляров класса

function Add: Tcollectionltem;

Добавляет к коллекции новый экземпляр класса

procedure Assign (Source: TPersistent) ; override;

Копирует коллекцию из объекта Source в данный объект

procedure BeginUpdate; virtual;

Отменяет перерисовку коллекции. Используется при внесении изменений в коллекцию

procedure Clear;

Удаляет из коллекции все элементы

procedure EndUpdate; virtual;

Отменяет действие метода BeginUpdate

function FindItemID(ID: Integer): TCollectionltem;

Возвращает объект коллекции с номером ID

function GetNamePath: string; override;

Возвращает имя класса коллекции во время выполнения, если коллекция не имеет владельца. Иначе возвращает название свойства класса, владеющего коллекцией

function Insert (Index: Integer): TCollectionltem;

Вставляет в коллекцию новый объект на место с номером Index

 
Класс TCollectionltem
Класс TCollectionltem инкапсулирует основные свойства и методы элемента коллекции (табл. 7.4). Свойства класса обеспечивают хранение информации о расположении элемента в коллекции.
Таблица 7.4. Свойства и методы класса TCollectionltem


Объявление

Описание

property Collection: Tcollection;

Содержит экземпляр класса коллекции, которой принадлежит данный элемент

property DisplayName: string;

Содержит имя элемента, которое представляет его в Редакторе коллекции

property ID: Integer;

Содержит уникальный номер элемента в коллекции, который не может изменяться

property Index: Integer;

Содержит порядковый номер элемента в коллекции. Он соответствует положению элемента в списке и может изменяться

Резюме


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

  •  Классы TStrings и TStringList обеспечивают применение списков строк.
  •   Класс TList инкапсулирует список указателей.
  •  Классы TCollection и TCollectionitem позволяют применять в компонентах и программном коде коллекции группы однородных объектов. 

В среде Delphi вы можете найти еще много полезных классов общего применения. В модуле CLASSES.PAS есть класс TBits, обеспечивающий побитное чтение и запись информации. В модуле CONTNRS.PAS есть классы xstack и TQueue (стек и очередь), а также потомки TList — TClassList, TComponentList и т. д. Они помогут вам решать типовые задачи быстро и без "изобретения велосипеда".

 

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г. Яндекс.Метрика