КЛАССЫ ОБЩЕГО НАЗНАЧЕНИЯ


В состав Delphi входит около 400 различных стандартных классов, простое перечисление которых заняло бы несколько страниц книги. В этой главе рассматриваются лишь некоторые самые важные классы общего назначения.
КЛАСС EXCEPTION - ОБРАБОТКА ИСКЛЮЧЕНИЙ
Класс Exception является прямым потомком базового класса тоь-ject. Вместе со своими потомками он предназначен для обработки исключительных ситуаций (исключений), возникающих при некорректных действиях программы: например, в случае деления на ноль, при попытке открыть несуществующий файл, при выходе за пределы выделенной области динамической памяти и т. п. В этом разделе рассматриваются основные свойства исключений и их использование для повышения надежности программ.
Примечание
При работе в среде Delphi эксперименты с исключениями плохо прослеживаются, т. к. при каждом исключении среда; перехватывает управление программой. В этом случае бывает полезно отменить такое поведение среды. Для этого вызовите опцию Tools. [.- -Debugger Options и на странице Languaqe Exception уберите флажок в переключателе Stop on delphi. Exceptions (для шэсдьиуш-лх версий Delphi выберите опцию меню Tools | Environent: Options и на странице Preference уберите флажок в персключателе Break on exception).
Защищенные блоки
Для обработки исключений в Object Pascal предусмотрен механизм защищенного блока:


except
<обработчики исключений>
else
<операторы>
end;

finally
<операторы>
end;

Try
<операторы>

Try
<операторы>

 
Защищенный блок начинается зарезервированным словом try (попытаться [выполнить]) и завершается словом end. Существуют два типа защищенных блоков - except (исключить) и finally (в завершение), отличающихся способом обработки исключения. В блоке except порядок выполнения операторов таков: сначала выполняются операторы секции try... except; если операторы выполнены без возникновения исключительной ситуации, работа защищенного блока на этом прекращается, и управление получает оператор, стоящий за end; если при выполнении части try возникло исключение, управление получает соответствующий обработчик в секции except, а если таковой не найден - первый из операторов, стоящих
За словом else. В блоке finally операторы В секции finally. . .end получают управление всегда, независимо от того, возникло ли исключение в секции try.. .finally или нет. Если исключение возникло, все операторы в секции try.. .finally, стоящие за “виновником” исключения, пропускаются, и управление получает первый оператор секции finally... end. Если исключения не было, этот оператор получает управление после выполнения последнего оператора секции try.. .finally.
Обработчики исключений в блоке except имеют такой синтаксис:
on <класс исключения> do <оператор>;
Здесь on, do - зарезервированные слова; <класс исключения> -класс обработки исключения; <оператор> - любой оператор Object Pascal, кроме оператора передачи управления goto на метку вне блока except.
Обратите внимание: имя класса служит своеобразным ключом выбора, а собственно обработка осуществляется оператором, стоящим за do (этот оператор может быть составным, так что обработка исключения может занимать произвольное количество операторов Object Pascal).
Поиск нужного обработчика осуществляется с начала списка вниз до тех пор, пока не встретится класс, способный обрабатывать исключение данного типа. Если подходящего класса не обнаружено, управление передается операторам, стоящим за словом else, а если таковых нет (часть else <операторы> может опускаться), выполняется умалчиваемая обработка исключения.
Если для программиста важен лишь сам факт возникновения исключения и несущественен тип связанной с ним ошибки, он может опустить в секции except.. .end обработчики вместе со словом else, оставив в ней лишь необходимый код реакции на любую ошибку:
try
except
ShowMessage('Ощибка!') ;
end;
Защищенные блоки могут вкладываться друг в друга на неограниченную глубину, т. к. везде, где в предыдущих описаниях использовались <операторы> ИЛИ <оператор>, могут использоваться любые операторы Object Pascal, в том числе и try... except или try...finally:
try
try finally
end;
except
on EMatchError do begin
try try end;
end;
end
end;
Класс Exception
Класс Exception является родительским классом для всех классов-исключений. Этот класс объявляется в модуле sysUtils следующим образом:
type
Exception = class(TObject)
private
FMessage: String;
FHelpContext: Integer;
public
constructor Create(const Msg: Strings);
constructor CreateFmt(const Msg: String;
const Args: array of const);
constructor CreateRes(Ident: Integers);
constructor CreateResFmt(Ident: Integer;
const Args: array of const) ;
constructor CreateHelp(const Msg: String; aHelpContext:
Integer) ;
constructor CreateFmtHelp(const Msg: String;
const Args: array of const; aHelpContext: Integers);
constructor CreateResHelp(Ident: Integer; aHelpContext:
Integer) ;
constructor CreateResFmtHelp(Ident: Integer;
const Args: array of const;
aHelpContext: Integers);
property HelpCoatext: Integer read FHelpContext write FHeipContext;
property Message: String read FMessage write FMessage;
end;
В классе определены целых 8 конструкторов для создания объекта. С их помощью можно прочитать текстовое сообщение из ресурса, отформатировать его, связать исключение с контекстной справочной службой. Свойство Message делает доступным частное поле FMessage, в котором содержится текстовое сообщение.
Стандартные классы исключений
В Delphi определены стандартные классы исключений, перечисленные в табл. 16.1. Именно эти имена, а также имена пользовательских классов могут использоваться в обработчиках исключении.

Таблица 16.1

 Важно помнить, что ищется самый первый из, возможно, нескольких обработчиков, класс которого способен обрабатывать данное исключение. Если, например, в списке первым стоит EAbort, который может обработать любое исключение, ни один из стоящих за ним обработчиков никогда не получит управления. Точно так же, если указан обработчик для класса EintError, за ним бесполезно размещать ОбработчикиEDivByZero, ERangeError или EIntOverflow:

try
except
// He имеет смысла делать так:
on EintError do .....;
on ERangeError do .....;
on EDivByZero do .....;
// Надотак:
on ERangeError do .....;
on EDivByZero do .....;
on EintError do .....;
end;
При возникновении исключительной ситуации объекты классов-обработчиков создаются и уничтожаются автоматически. Если программист пожелает использовать поля или методы класса-обработчика явно, он должен поименовать автоматически создаваемый объект. Для этого перед именем класса ставится идентификатор и двоеточие:
on EObject: EClassName do .....;
Для стандартных классов такой прием фактически позволяет использовать единственное строковое свойство Message со стандартным сообщением об ошибке, которое получают все наследники класса Exception. Исключение составляет класс EInOutError, в котором для программиста может представлять интерес целочисленное свойство ErrorCode с кодом ошибки ввода/вывода.
Например:
Reset(F) ;
while not EOF(F) do begin
end;
CloseFile(F) ;
except
on E: EInOutError do
ShowMessage('При выполнении файловой операции возникла'+ ' ошибка №'+ IntToStr(E.ErrorCode));
end;
Вызов исключения
В некоторых ситуациях программисту бывает необходимо инициировать собственное исключение. Для этого он использует зарезервированное слово raise (возбудить). Если это слово встретилось в секции try.. .exception или try.. .finally, немедленно начинают свою работу секции соответственно except... end и finally... end. Если оно встретилось в except.. .end или finally.. .end, считается, что данный защищенный блок на текущем уровне вложенности (блоки могут быть вложенными) завершил свою работу и управление передается вышестоящему уровню.
Слово raise возбуждает исключение самого общего класса Exception. Если программист желает возбудить исключение конкретного типа (не важно - стандартного или собственного), он должен явно указать класс создаваемого в этот момент объекта путем вызова его конструктора. Например, следующий оператор возбудит ошибку ввода/вывода:
raise EInOutError.Create('Ощибка!') ;
Такой прем - единственная возможность возбудить нестандартное исключение, обрабатываемое пользовательским классом.
Создание собственного класса
Программист может создать собственный класс обработки исключений, объявив его потомком Exception или любого другого стандартного класса (этим другим чаще всего бывает класс EAbort). Объявление нестандартного класса имеет смысл только тогда, когда вам необходимо научить программу распознавать некорректные наборы данных и соответствующим образом на них реагировать.
Пусть, например, в программе используется цикл ввода целочисленных значений из текстового файла, их проверки и преобразования. Проверка заключается в простом контроле неотрицательности очередного числа после ввода и его положительности после преобразования. Перед проверкой необходимо получить строку из файла (здесь может возникнуть ошибка EinOutError) и преобразовать ее в целую величину (здесь возможна ошибка EConvertError); после проверки осуществляется обработка величины, в процессе которой может возникнуть ошибка EIntError.
Создадим новый класс EIntCheckError и будем возбуждать исключение этого класса при обнаружении ошибки в данных:
type
EIntCheckError = class(EAbort)
end;
var
F: TextFile;
S: String;
k: Integer;
begin
try
// Готовимсякработе: открываемфайлAssignFile(F, FileName);
Reset(F); // Здесь возможнаошибка EinOutError // Циклввода-контроля-преобразованияwhile not EOF(F) do begin
// Вводим символы очередного числа
ReadLn(F,S);// Здесь возможна ошибка EinOutError
// Преобразуем символы в число
k := StrToInt(S); // Здесь возможна ошибка EConvertError
// Проверяем число
if k < 0 then
raise EIntCheckError.Create("Отрицательное число');
// Преобразуем число
..... // Здесь возможна ошибка EIntError
// Вновь проверяем число
if k <= 0 then
raise EIntCheckError.Create('He положительное число');
end;
except
on E: EIntCheckError do
ShowMessage(E.Message) ;
on EInOutError do
ShowMessage('Некорректная файловая операция');
on EConvertError do
ShowMessage('Ошибка в записи числа');
on EIntError do
ShowMessage('Ошибка преобразования');
end;
end;
В этом примере создается класс EIntCheckError, который ничем, кроме названия, не отличается от своего родителя EAbort. В реальной программе потомок обычно расширяет набор полей (свойств) своего родителя или перекрывает его методы; приведенный пример лишь иллюстрирует, что делать это необязательно. При неудачной проверке операторами
raise EIntCheckError.Create('Отрицательное число') ;
и
raise EIntCheckError.Create('Ошибка преобразования');
возбуждается исключение нового класса. При этом с помощью унаследованного конструктора create создается новый безымянный объект, а строковый параметр обращения к конструктору запоминается в поле FMessage и становится доступен с помощью свойства Message объекта. Обработчик исключения EIntCheckError именует объект идентификатором e и с помощью стандартной процедуры ShowMessage показывает его в небольшом окне на экране.
Пример наглядно показывает выгоды использования исключений. В принципе весь этот фрагмент можно было бы написать с многочисленными проверками if... then, но в этом случае логика программы стала бы запутанной, а сама программа - сложной в отладке.
КЛАСС TLIST - СПИСКИ
Класс TList позволяет создать набор из произвольного количества элементов и организовать индексный способ доступа к ним, как это делается при работе с массивом. Списки отличаются от массивов двумя важными особенностями. Во-первых, их размер может динамически меняться в ходе работы программы, фактически ограничиваясь лишь доступной памятью. Во-вторых, в списках могут храниться элементы разных типов.
Технически списки представляют собой массивы нетипизированных указателей на размещенные в динамической памяти элементы. Эти массивы размещаются в куче - отсюда возможность динамического изменения размеров списков; с другой стороны, входящие в списки нетипизированные указатели позволяют ссылаться на произвольные элементы.
Свойства класса:


property List: pPointerList;

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

property Capacity: Integers;

Содержит количество элементов массива указателей списка. Всегда больше Count. Если при добавлении очередного элемента Count стало равно Capacity, происходит автоматическое расширение списка на 16 элементов

property Count: Integer;

Количество элементов списка. Это свойство изменяется при добавлении или удалении элемента

property Items(Index: Integer): Pointers;

Возвращает указатель на элемент списка по его индексу. Самый первый элемент списка имеет индекс 0

 
Тип pPointerList определен следующим образом:
type
pPointerList = PPointerList;
TPointerList = array [0..MaxListSize] of Pointer;
Константа MaxListSize для Delphi 1 ограничена значением 16379 элементов. Для старших версий Delphi она ограничивается доступной памятью.
Следует учесть, что свойство count определяет количество помещенных в список элементов, в то время как capacity - текущую емкость списка. Если при добавлении очередного элемента обнаруживается, что емкость списка исчерпана, происходит наращивание емкости на фиксированную величину (для count < 5 - на 4 элемента, для 4 < count < 8 - на 8, для Count > 7 - на 16). При этом сначала резервируется память для размещения расширенного массива указателей, затем в нее копируется содержимое старого массива, после чего старый массив указателей уничтожается (занимаемая им память возвращается Windows).
Примечание
Если вы заранее знаете, сколько элементов необходимо поместить :в список, установите в начале работы нужное значение в свойство Саpacity - это снизит непроизводительные затраты времени на расширение списка.
Методы класса:


function Add(Item:
Pointer): Integer; procedure Clear;

Добавляет элемент item в конец ci;
вращает его индекс Очищает список, удаляя из него вес Не освобождает память, связанную удаленным элементом. Устанавлив: ства Count и Capacity значение 0

procedure Delete(Index:Integer);

Удаляет из списка элемент с индекс все элементы, расположенные за удаляемым, смещаются на одну позицию вверх

class procedure Er
ror(const Msg: Stringy; Data: Integer); virtual;

Возбуждает исключение ElistErr метрами Msg и Data  

procedure Ex
change (Indexl, Index2:Integer) ;

Меняет местами элементы с индексами index1 иI ndex2

function Expand: TList; function Extract(Item: Pointer): Pointer;

Расширяет массив, увеличивая Capacity Удаляет из списка элемент Item

function First: Pointer;

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

function IndexOf(Item:Pointer): Integer;

Отыскивает в списке элемент Item и возвращает его индекс

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

Вставляет элемент Item в позицию Index списка: новый элемент получает индекс Index, все элементы с индексами Index и больше увеличивают свой индекс на 1. При необходимости расширяет список

function Last: Pointer;
 

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

procedure Move(Curlndex,
Newlndex: Integers;  

Перемещает элемент в списке с позиции CurIndex в позицию Newlndex. Все элементы старого списка с индексами от Curlndex-1 до Newlndex уменьшают свой индекс на 1

procedure Pack;
 

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

function Remove(Item:
Pointer): Integer;

Отыскивает в списке элемент Item и удаляет его

procedure Sort(Compare: rListSortCompare);

Сортирует коллекцию с помощью функции Compare

Методы Add и insert получают указатель на вставляемый элемент. Чтобы воспользоваться ими, программист должен сам разместить в куче данные и получить соответствующий указатель. Точно так же методы Delete, Remove и Сlear не уничтожают распределенные в памяти данные, которые программист должен, если это необходимо, уничтожить сам.
Например:
var
List: TList;
Item: Pointer;
Value: AnyType;
begin
List := TList.Create; // Создаем список
Item := New(Value); // Размещаем в куче данные
List.Add(Item); // Добавляем элемент к списку .....
List.Remove(Item); // Удаляем элемент из списка
Dispose(Item); // Удаляем его из кучи
List.Free; // Удаляем ненужный список
end;
Метод sort сортирует список по критерию, устанавливаемому функцией compary. Тип TListSortCompare определен следующим образом:
TListSortCompare = function(Iteml, Item2: Pointer): Integer;
Таким образом, функция compare получает указатели на два элемента списка. Результат сравнения:

  • любое отрицательное число, если Item1 ^ <Item.2^;
  • 0,если Item1 ^ = Item2^;
  • любое положительное число, если Item1 ^ > Item2^.

Критерий сравнения данных устанавливается программистом и реализуется в функции Compare.
В следующем примере в список List помещается 20 случайных вещественных чисел, равномерно распределенных в диапазоне 0...1.
Список сортируется по возрастанию чисел и отображается в компоненте mmOutput (многострочный редактор из учебной формы fmExample).
type
PDouble = ^Double;
Function Comp(Iteml, Item2:. Pointer): Integer;
// С помощью этой функции реализуется сортировка чисел
begin
if PDouble(Iteml)^ < PDouble(Item2) ^ then
Result := -1 else
if PDouble(Iteml^ > PDouble (Item2) ^ then
Result := 1 else
Result := 0 end;
procedure TfmExample.bbRunClick(Sender: TObject);
// Обработчик нажатий кнопки bbRun выполняет основную работу
var
k: Integer;
List: TList;
pD: PDouble;
begin
List := TList.Create; // Создаемсписок
for k := 1 to 20 do // Наполняемего
begin
New(pD); // Резервируем память
pD^ := Random; // Помещаем в нее случайное число
List.Add(pD); // Добавляем к списку
end/List. Sort (Comp) ; // Сортируем список по возрастанию mmOutput.Lines.Clear;
{ Очищаем редактор mmOutput. В следующем цикле наполняем mmOutput и уничтожаем элементы List }
for k := 0 to List.Count-1 do
begin
pD := List[k]; // Очередное число из списка
mmOutput. Lines .Add (FloatToStr (pD^ );
{Помещаемв mmOutput}
Dispose(pD) // Уничтожаемчисло
end;
List.Free; // Уничтожаемсписок
end;
КЛАССЫ TSTRINGS И TSTRINGLIST НАБОРЫ СТРОК И ОБЪЕКТОВ
TStrings
Абстрактный класс TStrings инкапсулирует поля и методы для работы с наборами строк. От него порождены многочисленные специализированные потомки, обслуживающие наборы строк в таких компонентах, как TComboBox, TListBox, TRichEdit и др. Эти классы
(TComboBoxStrings, TListBoxStrings, TRichEditStrings и др.) объявляются в разделах Implementation соответствующих модулей (Stdctris, Сomctris и др.) и поэтому скрыты от браузера Delphi и не включены в Help-службу. Единственным доступным наследником TStrings является TStringList - полнофункциональный класс общего назначения.
Замечательной особенностью TStrings и его потомков является то обстоятельство, что элементами наборов служат пары строка-объект, в которых строка - собственно строка символов, а объект - объект любого класса Delphi. Такая двойственность позволяет сохранять в TStrings объекты с текстовыми примечаниями, сортировать объекты, отыскивать нужный объект по его описанию и т. д. Кроме того, в качестве объекта может использоваться потомок от TStrings, что позволяет создавать многомерные наборы строк.
Свойства класса:

Набор строк технически реализуется подобно TList - в виде массива указателей. Свойство Capacity показывает текущую длину этого массива, а свойство count - количество элементов, занятых в нем. Если при добавлении очередного элемента capacity окажется меньше count, происходит автоматическое расширение массива. При этом в динамической памяти резервируется место для размещения Capacity + 16 указателей, в новый массив переписывается содержимое старого массива, после чего старый массив уничтожается. Если вам известно количество элементов в создаваемом наборе строк, имеет смысл заранее нужным образом установить свойство capacity, чтобы сократить непроизводительные расходы на многократные расширения массива указателей.
Свойство commaText интерпретирует содержимое набора строк в виде одной длинной строки с элементами вида "первая строка", "вторая строка", "третья строка" и т. д. (каждая строка набора заключается в двойные кавычки и отделяется от соседней строки запятой; если в строке встречается символ “"”, он удваивается). Свойство Text интерпретирует содержимое набора в виде одной длинной строки с элементами, разделенными стандартным признаком eoln (#13#10).
Свойства Names И Values обрабатывают строки вида Name=Value.

Такие строки широко используются в различных файлах инициации, например, в файле win. ini. Методы класса:

Методы Add, Append, Insert, Clear И Т. П. В классе TStrings - абстрактные. Связано это с тем, что класс инкапсулирует их и таким
образом делает доступными во всех потомках, но он при этом не накладывает никаких ограничений на то, как располагаются в памяти строки и объекты. Каждый потомок решает эту задачу наиболее удобным для него способом. Например, потомок TStringList располагает строки и объекты в общей динамической памяти, для чего перекрывает все абстрактные методы своего родителя. Замечу, что? если вы создадите экземпляр класса TStrings с помощью его конструктора Create, компилятор предупредит вас о том, что этот экземпляр содержит абстрактные методы, так что пользоваться им нужно лишь в исключительных случаях.
TStringList
TStringList представляет собой полнофункциональный класс общего назначения и является прямым потомкам TStrings. Помимо перекрытых абстрактных методов своего родителя класс включает в себя такие дополнительные методы и свойства:


property Duplicates: TDu-plicates;

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

property Sorted: Boolean;

Признак необходимости сортировки строк в алфавитном порядке

property OnChange: TNotifyEvent;;

Определяет реакцию на изменение набора строк. Возникает после последнего изменения

property OnChanging: TNotifyEvent

Определяет реакцию на изменение набора строк. Возникает до очередного изменения

function Find(const S:String; var Index: Integer) : Boolean;

Ищет в наборе строку S и в случае успеха в параметре index возвращает ее индекс

 При sorted = True строки набора автоматически сортируются в алфавитном порядке. При этом свойство Duplicates разрешает коллизию, связанную с добавлением в набор строки, идентичной одной из ранее вставленных. Если Duplicates = dulgnore, идентичная строка отвергается и программе ничего об этом не сообщается; если Duplicates = duError, возбуждается исключение EListError; значение Duplicates = duAccept разрешает вставлять в набор сколько угодно идентичных строк.
Следует заметить, что сортировка строк в Windows 32 осуществляется не совсем так, как это происходит в MS-DOS или Windows 3-х. Чтобы убедиться в этом, советую прогнать следующий вариант учебной программы (см. В ней обработчик события OnClick кнопки bbRun создает два списка строк - List1и List2. Список List1 первоначально способен сортировать строки (в его свойство sorted устанавливается значение True). Затем в цикле от 32 до 255 (О...31 - это коды служебных символов) происходит наполнение обоих списков: в List1 помещается строка, содержащая символ и его код, а в List2 - наоборот, сначала код, а затем сам символ. Поскольку символьное представление кода дополняется до трех символов (в двузначных числах слева добавляется ведущий ноль), строки в списке List1 окажутся отсортированными по символу, а в списке List2 - по коду символа. Затем оба списка для наглядности объединяются и помещаются в редактор mmOutput.
procedure TfmExample.bbRunClick (Sender: TObject);
var
k: Byte;
Listi, List2: TStringList;
S: String;
begin
// Создаемдвасписка
List1 := TStringList.Create;
Listi.Sorted := True;
List2 := TStringList.Create;
// Цикл наполнения списков монотонно возрастающими кодами
for k := 32 to 255 do
begin
S := IntToStr(k); // Кодсимвола
if k<100 then
S := '0' + S;// Двузначное число дополняем ведущим нулем
// Формируем строку Listi из символа + табуляция + код символа Listi.Add(Char(k) + #9 + S) ;
// Формируем строку List2 из кода + табуляция + символ
List2.Add(S + #9 + Char(k));
end;
// Объединяем оба списка
Listi.Sorted := False; // Отключаем сортировку List1
for k := 0 to List1.Count-1 do
List1[k] := List1[k] + #9 + List2[k];
// Переносимрезультатв mmOutput mmOutput.Lines.Assign(List1);
// Уничтожаем List1 и List2 Listi.Free;
List2. Free;
end;
Следует прокомментировать два момента. Во-первых, с помощью единственного оператора
mmOutput.Lines.Assign(List1);
все строки List1 помещаются в свойство Lines редактора mmOutput. Это возможно из-за того, что mmOutput. Lines и Listi имеют общего родителя TStrings, который умеет копировать родственные наборы строк с помощью своего метода Assign. Во-вторых, перед объединением строк мы отключили свойство Sorted списка Listi. если этого не сделать, любое изменение строк в отсортированном списке привело бы к исключентю EStringListError.
Как видим, строки в 32-разрядных Windows сортируются не с учетом внутреннего кода символа, а с учетом “смысла”: в начале располагаются все знаки препинания и разного рода “мусор”, затем идут цифры, буквы латинского алфавита и символы кириллицы. Буквы упорядочены парами - сначала заглавная, за ней строчная - и не идут сплошным массивом. “Виновником” такой сортировки является API-функция AnsiCompareText, К который обращается метод TStringList. Quicksort. Если вам понадобится отсортировать так, как это принято в MS-DOS или Windows З.х, т. е. по коду символа, проделайте следующее.

  1. Разыщите в каталоге source | Rtl | common исходный файл classes . pas и скопируйте его в ваш рабочий каталог (в предыдущих версиях этот файл располагался в каталоге Source | vci). Если вы не найдете этого файла, вы не сможете изменить сортировку, т. к. в классе TStringList метод Quicksort, отвечающий за сортировку, определен в секции private и, следовательно, недоступен наследникам.
  2. В раздел implementation этого модуля сразу после предложения Uses поместите такое описание функции AnsiCompareText:

Function AnsiCompareText(SI, S2 : String): Integer;
begin
if S1 < S2 then Result := -1
else if SI == S2 then Result := 0
else Result := 1
end;
3. С помощью опции Project | Add To Project добавьте измененный модуль classes к вашему проекту и сделайте новый прогон программы. Теперь оба столбца будут идентичны.
ГРАФИЧЕСКИЙ ИНСТРУМЕНТАРИЙ
Богатство изобразительных возможностей Windows связано с так называемым дескриптором контекста графического устройства DC (Device Context) и тремя входящими в него инструментами - шрифтом, пером и кистью. В Delphi созданы специализированные классы-надстройки, существенно упрощающие использование графических инструментов Windows: для контекста - класс TCanvas, для шрифта - TFont, для пера - ТРеп и для кисти - TBrush.
Связанные с этими классами объекты автоматически создаются для всех видимых элементов и становятся доступны программе через свойства Canvas, Font, Pen и Brush.
Класс TFont
С помощью класса TFont создается объект-шрифт для любого графического устройства (экрана, принтера, плоттера и т. п.).
Свойства класса:

Для некоторых случаев может оказаться полезным метод
procedure Assign(Source: TPersistent);
с помощью которого значения свойств шрифтового объекта source присваиваются свойствам текущего шрифта. Метод не изменяет свойство pixeiperinch, поэтому его можно использовать для создания шрифта принтера по экранному шрифту и наоборот.
Класс ТРеn
С помощью класса треп создается объект-перо, служащий для вычерчивания линий.
Свойства класса:

 Стили линий показаны на
Класс TBrush
Объекты класса TBrush (кисти) служат для заполнения внутреннего пространства замкнутых фигур.
Свойства класса:


property Bitmap: TBitmap;

Содержит растровое изображение, которое будет использоваться кистью для заполнения. Если это свойство определено, свойства Color и Style игнорируются

property Color: TColor;

Цвет кисти

property Handle: Integer;

Дескриптор кисти. Используется при не посредственном обращении к API- функциям Windows

property Style: TBrushStyle;

Стиль кисти (см.

Класс TCanvas
Этот класс создает “канву”, на которой можно рисовать чертежными инструментами - пером, кистью и шрифтом. Объекты класса ЕСаnvas автоматически создаются для всех видимых компонентов, которые должны уметь нарисовать себя. Они инкапсулируют объекты Font, pen, Brush, а также многочисленные методы, использующие эти объекты.
Свойства класса:


property Brush: TBrush; property ClipRect: TRect;

Объект-кисть Определяет текущие размеры области, нуждающейся в прорисовке

property CopyMode: TCopyMode;

Устанавливает способ взаимодействия растрового изображения с цветом фона

property Font: TFont;

Объект-шрифт

property Handle: Integer;

Дескриптор канвы. Используется при непосредственном обращении к API-функциям Windows

property LockCount: In
tegers;
 
 

Счетчик блокировок канвы. Увеличивается на единицу при каждом обращении к методу Lock и уменьшается на единицу при обращении к Unlock

property Pen: TPen;

Объект-перо

property PenPos:TPoint;

Определяет текущее положение пера в пикселях относительно левого верхнего угла канвы

property Pixels[X,Y:Integer]: TColor;

Массив пикселей канвы
 
 

Свойство copyMode используется при копировании части одной канвы (источника) в другую (приемник) методом copyRect и может иметь одно из следующих значений:

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

Дополнительные возможности API-функций


Замечу, что все богатство изобразительных возможностей Windows далеко не исчерпывается набором свойств и методов класса TCanvas: этот класс инкапсулирует лишь наиболее популярные приемы работы с чертежными инструментами. В этом разделе перечисляются некоторые функции Windows, которые не инкапсулирует класс TCanvas и которые способны значительно разнообразить текстовый вывод (именно он наиболее обеднен узкими рамками TCanvas).
Некоторые текстовые функции API

 Отдельные поля структуры TLogFont для функции CreateFontIndirect имеют следующий смысл:
if Height - высота шрифта в пунктах (1 пункт = 1/72 дюйма); если больше 0, определяет высоту “знакоместа” (с учетом выступающих над заглавным символом элементов в буквах Е, И), если меньше нуля - высоту “чистого” символа, если 0 - высоту выбирает Windows;
if width - средняя ширина символа; если 0, ширину устанавливает Windows;
ifEscapment - угол наклона базовой линии текста в десятых долях градуса относительно горизонтального направления; положительные значения - поворот по часовой стрелке; в Windows 95/98 совпадает СIfOrientation;
iforientation - угол наклона символов по отношению к базовой линии; в Windows NT для шрифтов True Type может отличаться от ifEscapment; для этого следует установить режим устройства отображения равным gm_Advanced (по умолчанию устанавливается gm_Compatible);
IfWeight - плотность шрифта (fm_DontCare=0 - плотность выбирает Windows; fm_Thin=100 - очень тонкий шрифт;
fm_ExtraLight=200 - очень светлый; fm_Light=300 - светлый;
fm_Normal=400 - нормальный; fm_Medium=500 - утолщенный;
fm_SemiBold=600 - полужирный; fm_Bcld=700 - жирный;
fm_ExtraBold=800 - усиленный; fm_Heavy=900 - тяжелый);
ifitalic, ifunderiine, ifStrikeOut - ненулевое значение означает соответственно наклонный, перечеркнутый и подчеркнутый шрифт;
IfCharSet - Набор символов (ANSI_CharSet=0, Default_CharSet=l;
Symbol_CharSet=2;ShiftJis_CharSet=128;OEM_CharSet=255);
ifoutprecision - точность представления шрифта; рекомендуется out__TT_prec (выбирает True Type и векторные шрифты, если есть несколько разновидностей одноименных шрифтов) или out_TT_oniy_prec (только True Type);
ifclipprecision - определяет точность отсечения надписи границами области прорисовки (Clip_Character_Precis, Clip_Embedded, Clip_Mask, Clip_TT_Always, Clip_Default_Precis - рекомендуется, Clip_LH_Angles, Clip_Stroke_Precis);
IfQuality - Определяет качество прорисовки (Default_Quality, Draft_Quality,Proof_Quality);
ifpitchAndFamily - в четырех младших разрядах указывается тип шрифта, в четырех старших ~ его семейство;
IfFaceName - имя гарнитуры шрифта.
Вот как реализован этот пример.
procedure TForm1.FormPaint(Sender:TObject) ;
var
X: Integer;
LF: TLogFont;
Fnt: HFont;
const
Text = 'Лучшая в мире система программирования';
begin
// Определяем параметры нового шрифта
FillChar(LF, SizeOf(LF), 0) ;
with LF do
begin
If Height := 20;
If Weight := fw_Normal;
If Underline := 1;
If Escapement := 450;
StrPCopy(lfFaceName, 'Courier New Cyr');
end;
with Forml.Canvas do
begin
// Создаемшрифт
Fnt := CreateFontIndirect(LF) ;
// Присваиваемегодескрипторшрифтуканвы
Font.Handle := Fnt;
// Выводим текст под углом +45 градусов
Text0ut(0, 300, Text);
X := TextWidth(Text) ;
DeleteObject(Fnt); // Удаляем ненужный шрифт
// Изменяем параметры шрифта
with LF do
begin
If Height := 90;
IfEscapement := -900;
IfWeight := fw_Heavy;
StrPCopy(LF.lfFaceName, 'Arial Cyr');
end;
Fnt := CreateFontIndirect(LF); // Создаемновыйшрифт
Font.Handle := Fnt;
Font.Color := clRed;
// Выводим с наклоном -90 градусов
TextOut(X-10, 10, 'Delphi 5');
DeleteObject(Fnt); // Удаляем ненужный шрифт
end;
end;  
Параметр Format функции DrawText может содержать один или несколько следующих флагов.
Возможные значения параметра Format функции DrawText


dt Bottom

Текст прижимается к нижней части области Rect

dtCalcRect

Разрешает динамически изменять размеры области Rect

dtCenter

Текст центрируется по горизонтали

dtEditControl
 

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

dtExpandTabs

Символы табуляции заменяются пробелами

dt ExternalLeading

В высоту строки включается высота межстрочного интервала

dtLeft

Текст прижимается к левой части области Rect

dtNoClip

Текст не отсекается границами Rect

dtNoPrefix

Символы & не заменяются подчеркиванием

dtRight

Текст прижимается к правой части области Rect

dt SingleLine

Весь текст выводится единственной строкой, символы EOLN игнорируются

dt TabsStop

Символы табуляции не заменяются пробелами

dtTop

Текст прижимается к верхней части области R'ect

dtVCenter

Текст центрируется по вертикали

dtWordBreak

Разрешает переход на новую строку при достижении пра вой границы Rect; разрыв строки - на границе слова; символы EOLN также переводят вывод на следующую строку

Если установлен флаг dt_caicRect, функция изменяет высоту и ширину прямоугольника так, чтобы вывести весь текст, но сам текст не выводится. Если в тексте несколько строк, ширина вывода не меняется. Функция возвращает истинную высоту прямоугольника вывода.
Параметр options функции ExtTextOut может быть комбинацией следующих значений:
eto_Сlipped - текст будет отсекаться границами Rect;
eto_Gliph_index - блокирует обработку языковым драйвером;
eto_opaque - фон перерисовывается заново;

eto_RTLReading - вывод для чтения справа налево. При выводе текста стандартными методами rcanvas всегда заново прорисовывается фон символов (цвет фона возвращает функция GetBkColor). Если цвет фона символов отличается от фона канвы, вывод сопровождается неприятными побочными эффектами. Если в предыдущем примере для формы оставить стандартный цвет ciFaceBtn, окно вывода будет таким, как на Конечно, с помощью функции setBkcoior можно установить цвет формы совпадающим с цветом канвы, однако это не всегда возможно. Ясно, что установить переменный цвет функцией SetBkcoior невозможно. Более того, заглавные надписи программ Setup.exe также традиционно выводятся утолщенным наклонным шрифтом Times New Roman белыми буквами с черной тенью. Реализовать такой эффект достаточно просто: нужно вообще отказаться от прорисовки фона, установив с помощью функции SetBkMode режим Transparent, и вывести надпись дважды: первый раз черным цветом, а второй -белым, сместив вторую надпись немного влево и вверх относительно первой. Следующий листинг иллюстрирует сказанное.
procedure TForm1.FormPaint(Sender: TObject);
var
Y: Integer;
Blue: Byte;
const
Text = 'Фон для программы Setup.exe';
begin
with Forml.Canvas do
begin
for Y := 0 to Forml.Height-1 do
begin
// Уменьшаем интенсивность цвета с ростом ординаты Y
Blue := Round($FF*(Forml.Height-Y)/Forml.Height);
Pen.Color := RGB(0, 0, Blue); // Формируемцвет
MoveTo(0, Y); // Чертимлинию
LineTo(Forml.Width-1, Y) ;
end; // for Y := 0 to Forml.Height-1 do Font.Size := 32;
Font.Style := [fsBold, fsltalic, fsUnderline];
Font.Name := 'Times New Roman";
// Это обращение накладывает текст на фон SetBkMode(Handle, Transparent);
// Сначала выводим тень надписи
Font.Color := clBlack;
Text0ut(40, 30, Text);
// ТеперьсамунадписьFont.Color := clWhite;
Text0ut(36, 26, Text)
end; // with Forml.Canvas do end;
Замечу, что любая заливка фона, в том числе его прорисовка, реализуется с помощью кисти. Поэтому отказаться от прорисовки фона текста можно, если установить стиль кисти bsciear: вместо
SetBkMode(Handle, Transparent);
можно использовать
Brush.Style := bsClear;
Области
К сожалению, в класс TCanvas не включена еще одна изобразительная возможность Windows - области (Regions). Области - такие же графические объекты, как перо, кисть, шрифт. Они образуются с помощью комбинации простейших геометрических фигур - прямоугольников, многоугольников, эллипсов. Замечательной особенностью областей является возможность создания с их помощью непрямоугольных кнопок, цветовых областей, окон. А вот как оно было создано:
uses
Forms,
Unit1 in 'Unitl.pas' {Formi}, Windows; // Этот модуль экспортирует функции API
{$R *.RES} var
Rgn: Cardinal;
begin
// Сначала создаем обычное окно:
Application.CreateForm(Tform1, Form1);
with Formi.Canvas, Formi do
begin
// Теперь создаем в нем эллиптическую область
Rgn := CreateEllipticRgn(0, 0, Width, Height);
// и показываем ее вместо окна
SetWindowRgn(Handle, Rgn, True);
end;
Application.Run;
end.
Ниже перечислены основные функции для работы с областями.
Работа с областями

Параметр combineMode в функции combineRgn может значения:
rgn_and - включает в результат общие части областей; rgn_copy -копирует область Rgnl В DestRgn; RGN_DIFF - исключает изRgnl часть, принадлежащую Rgn2; rgn_or - объединяет области; rgn_xor -включает в результат только те части областей, которые не принадлежат им одновременно. Область DestRgn уже должна существовать и иметь размеры, достаточные для размещения объединенной области. При обращении к функции createPoiygonRgn параметр Poly FillMode может иметь значения: Alternate И Winding. В первом случае заполнение многоугольника идет последовательно между двумя близлежащими его сторонами: сначала между 1-й и 2-й, затем между 2-й и 3-й и т. д. В режиме winding заполняется все внутреннее пространство области.
Во всех случаях Windows автоматически проводит линию между последней и первой точкой многоугольника, делая его замкнутым.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls;
tуре
Tform1 = class (TForm)
PaintBoxl: TPaintBox;
PaintBox2: TPaintBox;
Button1: TButton;
procedure ButtonlClick(Sender: TObject);
private
{ Private declarations } public
{ Public declarations } end;
var
Form1: Tform1;
implernentation
$R *.DFM)
procedure TFormI.ButtonlClick(Sender: TObject);
var
Rgnl, Rgn2: Cardinal;
const
Points: array [1..5, 1..2] of Integer =
C(91, 0), (160, 183), (0, 70), (183, 70), (23, 183));
begin
Rgn1 := CreatePolygonRgn(Points, 5, Alternate);
Rgn2 := CreatePolygonRgn(Points, 5, Winding);
with PaintBoxl.Canvas do begin
Brush.Color := clBlack;
FillRgn(Handle, Rgnl, Brush.Handle);
end;
with PaintBox2.Canvas do begin
Brush.Color := clBlack;
FillRgn(Handle, Rgn2, Brush.Handle) ;
end;
end;
end.
Обратите внимание: прорисовка и объединение областей доступны, только если области видны в окне (для создания предыдущего рисунка нельзя, например, использовать обработчик формы OnActivate).
Функция SetWindowRgn, как уже отмечалось, поручает прорисовку окна самой Windows, при этом фактически прорисовывается не область, а лишь та часть окна, которая ограничена ею. Любые заливки области, ее очерчивание и объединение с другими областями игнорируются.
Классы TGraphic и TPicture
Важное место в графическом инструментарии Delphi занимают классы TGraphic и TPicture.
TGraphic - это абстрактный класс, инкапсулирующий общие свойства и методы трех своих потомков: пиктограммы (TIcon), метафайла (TMetafile) и растрового изображения (TBitmap). Общей особенностью потомков TGraphic является то, что обычно они сохраняются в файлах определенного формата. Пиктограммы представляют собой небольшие растровые изображения, снабженные специальными средствами, регулирующими их прозрачность. Для файлов пиктограмм обычно используется расширение ico. Метафайл - это изображение, построенное на графическом устройстве с помощью специальных команд, которые сохраняются в файле с расширением wmf или emf. Растровые изображения - это произвольные графические изображения в файлах со стандартным расширением bmp.
Свойства класса TGraphic:


property Empty: Boolean;

Содержит True, если с объектом не связано графическое изображение

property Height: Integer;

Содержит высоту изображения в пикселях

property Modified: Boolean;

Содержит True, если графический объект изменялся

property Palette: HPALETTE;

Содержит цветовую палитру графического объекта

property PaletteModified: Boolean;

Содержит True, если менялась цветовая палитра графического объекта

property Transparent: Boolean;

Содержит True, если объект прозрачен для фона, на котором он изображен

property Width: Integer;

Содержит ширину изображения в пикселях

Методы Класса TGraphic:

 procedure LoadFromClipooardFormat (AFormat: Word;AData: THandle; APalette:HPALETTE) ; 

Ищет в буфере межпрограммного обмена Clipboard зарегистрированный формат AFormat и, если формат найден, загружает из буфера изображение AData и его палитру Apalette

procedure LoadFromrile(const FileName:String) ;

Загружает изображение из файла FileName 

procedure LoadFromStream(Stream: TStream);

Загружает изображение из потока данных Stream

procedure SaveToClipboardFormat (var AFormat: Word;var AData: THandle; varAPalette: HPALETTE);

Помещает графическое изображение Adata и его цветовую палитру APalette в буфер межпрограммного обмена в формате Af ormat

procedure SaveToFile(constFileName: Strings;

Сохраняет изображение в файле FileName  

procedure SavePoStream(Stream: TStream);

Сохраняет изображение в потоке Stream

Полнофункциональный класс TPicture инкапсулирует в себе все необходимое для работы с готовыми графическими изображениями - пиктограммой, растром или метафайлом. Его свойство Graphic может содержать объект любого из этих типов, обеспечивая нужный полиморфизм методов класса.
Свойства класса TPicture:


property Bitmap: TBitmap;

Интерпретирует графический объект как растровое изображение

property Graphic: TGraphic;

Содержит графический объект

property Height: Integer;

Содержит высоту изображения в пикселях

property Icon: TIcon;

Интерпретирует графический объект как пиктограмму

property Metafile: TMetafile;

Интерпретирует графический объект как метафайл

property width: Integer;

Содержит ширину изображения в пикселях

Методы класса TPicture:

procedure Assign(Source: TPersistent) ;

Связывает собственный графический объект Graphic с объектом Source

procedure LoadFromClipboardFormat
(AFormat: Word;AData: THandle;
APalette:HPALETTE) ; 

Ищет в буфере межпрограммного обмена Clipboard зарегистрированный формат AFormat и, если формат найден, загружает из буфера изображение AData и его палитру APalette

procedure LoadFromFile(const FileName:String);

Загружает изображение из файла FileName 

class procedure Register; ClipboardFormat(AFormat:
Word; AGraphicClass: TGraphicClass) ;

Используется для регистрации в Clipboard
нового формата изображения
 
 

class procedure Register; FileFormat (const AExtension, ADescription: String; AGraphicClass: Tgraphic Class) ;

Используется для регистрации нового файлового формата
 

class procedure RegisterFileFormatRes(const AExtension: String; ADescriptionResID: Integer; Agraphic Class: TGraphicClass);

Используется для регистрации нового формата ресурсного файла  

procedure SaveToClipboardFormat (var AFormat: Word; var AData: THandle; varAPalette: HPALETTE);

Помещает графическое изображение AData и его цветовую палитру APalette в буфер межпрограммного обмена в формате AFormat

procedure SaveToFile(const
FileName: Strings;

Сохраняет изображение в файле FileName
 
 

class function SupportsClipboardFormat(AFormat: Word): Boolean;

Возвращает True, если формат Aformat зарегистрирован в буфере межпрограммного обмена Clipboard  

class procedure UnregisterGraphicClass(AClass:TGraphicClass);

Делает недоступными любые графические объекты класса Aclass

 

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