Property NumberProp3:integer
read Fnum3 write Fnum3 Stored Func3;
В первом случае указано, что необходимо сохранять текущее значение свойства, во втором случае – не сохранять, в третьем – сохранять, если функция Func3 возвращает True.
Команда Index позволяет обеспечить гибкость при объявлении методов доступа Read и Write к полям. Рассмотрим это на примере. Пусть два свойства IntProp1 и IntProp2 для доступа к полям FIntProp1 и FIntProp2 используют одни и те же подпрограммы:
Property IntProp1:integer Index 1
read GetIntProp write SetIntProp;
Property IntProp2:integer Index 2
read GetIntProp write SetIntProp;
Для указания того, что свойство IntProp1 работает с полем FIntProp1 а IntProp2 – с полем FIntProp2, используется команда Index. В данном случае число после слова Index указывает, какое поле следует использовать, например, подпрограммы GetIntProp и SetIntProp можно определить так:
Function <имя класса>.GetIntProp
(pIndex:integer):integer;
Begin
Case pIndex of
1:result:=FIntProp1;
2:result:=FIntProp2;
end;
end;
Procedure <имя класса>.SetIntProp
(pIndex:integer;pValue:integer);
Begin
Case pIndex of
1: FIntProp1:= pValue;
2: FIntProp2:= pValue;
end;
end;
Команда Dispid применяется при работе с объектами OLE.
ПРИМЕР 16
Пусть требуется построить на форме три геометрические фигуры: круг, квадрат, эллипс (рис. 36).
Рис. 36 Форма с вариантом решения примера 16.
Необходимо обеспечить возможность изменения цвета каждой фигуры. Пусть будет по два цветовых варианта каждой фигуры.
Для решения задачи построим четыре класса. Первый класс назовём TDrawArea. Включим в него следующие действия:
1) Инициализация всех полей;
2) Рисование фигуры;
Остальные три класса определяют конкретную реализацию рисования круга, квадрата и эллипса. Программа приводится ниже.
unitPRIM16;
Interface
uses Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
Type
TForm1 = class(TForm)
Panel1: TPanel;
btnRedCircle: TButton;
btnBlueCircle: TButton;
btnBlackSquare: TButton;
btnWhiteSquare: TButton;
btnYellowEllipse: TButton;
btnGreenEllipse: TButton;
Button1: TButton;
procedure AllBtnClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
end;
ArrayColor=array[1..6] of TColor;
TDrawArea = class(TPersistent)
Private
x1,y1,x2,y2:integer;
FArrayBrushColor: ArrayColor;
FPenColor: TColor;
function GetBrushColor(pIndex:integer): TColor;
Public
constructor InitColor;
constructor InitXY(NewX1,NewY1,NewX2,NewY2:
integer);
Property PPenColor: TColor read FpenColor
write FpenColor Default clBlack;
property PBrushColor[pIndex:integer]: TColor
read GetBrushColor;
procedure DrawFig;virtual;abstract;
procedure DrawIt;
end;
TSquare = class(TDrawArea)
procedure DrawFig;override;
end;
TEllipse = class(TDrawArea)
procedure DrawFig;override;
end;
TCircle = class(TDrawArea)
procedure DrawFig;override;
end;
var Form1: TForm1;
MySquare:TSquare;
MyEllipse:TEllipse;
MyCircle:TCircle;
Implementation
{$R *.DFM}
Constructor TDrawArea.InitColor;
begin
FArrayBrushColor[1]:=clRed;
FArrayBrushColor[2]:=clBlue;
FArrayBrushColor[3]:=clBlack;
FArrayBrushColor[4]:=clWhite;
FArrayBrushColor[5]:=clYellow;
FArrayBrushColor[6]:=clGreen;
End;
Constructor TDrawArea.InitXY(NewX1,NewY1,NewX2,NewY2:
integer);
begin
x1:=NewX1;
y1:=NewY1;
x2:=NewX2;
y2:=NewY2;
end;
Function TDrawArea.GetBrushColor(pIndex:integer):
TColor ;
begin
result:=-1;
if pIndex in [1..6] then
result:=FArrayBrushColor[pIndex];
end;
procedure TDrawArea.DrawIt;
begin
DrawFig;
end;
procedure TSquare.DrawFig;
begin
Form1.Canvas.Rectangle(x1,y1,x2,y2);
end;
procedure TCircle.DrawFig;
var Nx1,Ny1,Nx2,Ny2:integer;
begin
Nx1:=x1-x2;
Ny1:=y1-x2;
Nx2:=x1+x2;
Ny2:=y1+x2;
Form1.Canvas.Ellipse(Nx1,Ny1,Nx2,Ny2);
end;
procedure TEllipse.DrawFig;
begin
Form1.Canvas.Ellipse(x1,y1,x2,y2);
end;
procedure TForm1.AllBtnClick(Sender: TObject);
begin
if (Sender as Tbutton=btnRedCircle) or
(Sender as Tbutton=btnBlueCircle) then begin
if not assigned(MyCircle) then begin
MyCircle:=TCircle.Create;
MyCircle.InitColor;
MyCircle.InitXY(50,50,40,0);
Form1.Canvas.Pen.Color:=MyCircle.PPenColor;
end;
if Sender as Tbutton = btnRedCircle then begin
Form1.Canvas.Brush.Color:=MyCircle.PBrushColor[1];
MyCircle.DrawIt;
end;
if Sender as Tbutton = btnBlueCircle then begin
Form1.Canvas.Brush.Color:=MyCircle.PBrushColor[2];
MyCircle.DrawIt;
end;
end;
if (Sender as Tbutton=btnBlackSquare) or
(Sender as Tbutton=btnWhiteSquare) then begin
if not assigned(MySquare) then begin
MySquare:=TSquare.Create;
MySquare.InitColor;
MySquare.InitXY(110,10,190,90);
Form1.Canvas.Pen.Color:=MySquare.PPenColor;
end;
if Sender as Tbutton = btnBlackSquare then begin
Form1.Canvas.Brush.Color:=MySquare.PBrushColor[3];
MySquare.DrawIt;
end;
if Sender as Tbutton = btnWhiteSquare then begin
Form1.Canvas.Brush.Color:=MySquare.PBrushColor[4];
MySquare.DrawIt;
end;
end;
if (Sender as Tbutton=btnYellowEllipse) or
(Sender as Tbutton=btnGreenEllipse) then begin
if not assigned(MyEllipse) then begin
MyEllipse:=TEllipse.Create;
MyEllipse.InitColor;
MyEllipse.InitXY(220,10,280,90);
Form1.Canvas.Pen.Color:=MyEllipse.PPenColor;
end;
if Sender as Tbutton = btnYellowEllipse then begin
Form1.Canvas.Brush.Color:=MyEllipse.PBrushColor[5];
MyEllipse.DrawIt;
end;
if Sender as Tbutton = btnGreenEllipse then begin
Form1.Canvas.Brush.Color:=MyEllipse.PBrushColor[6];
MyEllipse.DrawIt;
end;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if assigned(MyCircle) then MyCircle.Free;
if assigned(MySquare) then MySquare.Free;
if assigned(MyEllipse) then MyEllipse.Free;
close;
end;
End.
В данном примере показано, как работать со свойствами типа Array. Следует обратить внимание, что каждый из трех используемых объектов должен строиться один раз. Для проверки существования объекта используется функция Assigned. При выходе из программы (Button1Click) все объекты разрушаются. В данной программе показано, как использовать один обработчик событий (AllBtnClick) для всех шести кнопок построения геометрических фигур. Используемые конструкторы InitColor и InitXY созданы не для построения объектов, а для инициализации данных, поэтому в их описании отсутствует вызов Inherited.
ФАЙЛОВЫЕ ТИПЫ
Тип файл представляет собой последовательность элементов одного типа, обычно расположенных на внешнем устройстве, например, на жестком диске. Можно выделить три основных типа файлов на физическом устройстве:
1. Данные в файле располагаются в виде строк разной длины. Каждая строка заканчивается двумя символами #13 #10 (#13 – возврат каретки, #10 – переход строки). Эти символы отделяют строки друг от друга. Максимальный размер строки ограничен, чаще всего он равен 128 символов, можно увеличить этот размер до максимального, равного 255 символам. При поиске нужной информации в таком файле необходимо найти #13 #10, прочитать найденную строку и проверить, есть ли заданная информация в этой строке, затем опять следует искать #13 и #10 и т.д. Таким образом, поиск может осуществляться, последовательно читая этот файл только сначала, т.е. файл рассматривается как один массив строк, разделенных символами #13 #10. Если нужно вставить информацию в середину такого файла, то это можно сделать путем переписывания старого файла в новый со вставкой новых строк и последующим удалением старого файла. Операционная система допускает дописывание информации в конец файла. В соответствии со свойствами, такой файл называют файлом последовательного доступа или текстовым.
2. Данные представляются в виде записей одинаковой длины. Никаких разделителей между записями нет. Операционная система может расположить головку считывания-записи информации на любой байт (установить файловый указатель). Так как все записи одинаковой длины, файловый указатель операционной системой может быть установлен на начало любой записи, таким образом, получается, что все записи будто бы пронумерованы. Первая запись нумеруется числом 0. Если длина записи равна 80 байт, то установку файлового указателя на начало второй записи (запись с номером 1) операционная система выполняет на отметке 80 байт. Эту запись можно прочитать или перезаписать. Такие файлы являются типизированными - файлами прямого доступа (в отличие от текстовых файлов).
3. В данном случае файлы рассматриваются как последовательность байт. Эти файлы являются файлами прямого доступа с длиной записи, чаще всего, равной 1 байту. С помощью такого подхода можно прочитать любой файл, но трудно интерпретировать информацию.
При работе с файлами автоматически проверяются ошибки ввода или вывода, если включена (по умолчанию) директива {$I+}. В этом случае при возникновении ошибки программа завершается. Если директива проверки файловых ошибок отключена {$I-}, то программа продолжает выполняться и можно проверить результат работы с файлом с помощью стандартной функции IOResult.
ТЕКСТОВЫЕ ФАЙЛЫ
Этот тип файлов объявляется с помощью файловой переменной типа TextFile: Var T : TextFile;
Перед тем, как начинать работу с файлом, необходимо файловую переменную связать с конкретным файлом. Это осуществляется с помощью следующей процедуры:
AssignFile(<ф.п.>, Name);,
где ф.п. – файловая переменная, Name – строка типа String, содержащая имя файла, например, AssignFile(T, ‘a.txt’);
Строка Name может содержать не только имя файла, но и путь к файлу.
По окончании работы с файлом его нужно закрыть процедурой CloseFile(<ф.п.>) Это требование обязательно должно соблюдаться для файлов, в которые записывалась информация. С помощью файлов можно вводить информацию в память, хранить информацию, передавать её от одних программных единиц к другим. Для чтения и записи информации используются встроенные стандартные процедуры.
Перед чтением информации необходимо явно указать, что файл будет использоваться только для чтения с помощью процедуры Reset(<ф.п.>) – эта процедура устанавливает файловый указатель на начало файла. Чтение информации осуществляется с помощью следующих процедур:
Read(<ф.п.>, <список>);
ReadLn(<ф.п.>, <список>);
Вторая процедура помогает полностью читать строку вместе с символами #13 #10. Первая процедура читает элемент или несколько элементов строки, но в пределах одной строки. Например, Read(Т, a, b, c); ReadLn(T, a, b, c);
Если a, b, c – строковые переменные, то первый оператор заполнит данными только одну переменную a (b и c останутся пустыми).
Текстовые файлы имеют одну особенность: несмотря на то, что файл состоит из строк, файл может содержать, наряду со строковыми данными, и другие типы данных, например, числовые. Прочитать из текстового файла можно информацию следующих типов: целый, вещественный, символьный, строковый. Дополнительно к перечисленням типам записывать можно ещё логический тип информации.
При чтении чисел автоматически происходит перекодирование информации в двоичный код. Если элементы не строковые, то в переделах одной строки файла может находиться несколько элементов, обязательно отделенных друг от друга разделителями. В качестве разделителей используются следующие символы: пробел, символ табуляции, возврат каретки (#13). При подготовке информации необходимо соблюдать эти требования – записывать в явном виде разделители. Процедуры Read и ReadLn читают информацию последовательно по одному символу (в том числе читаются #13, #10 и #26 - конец файла), причём, если чтение происходит не в строковые переменные, то значимыми для Read являются все виды разделителей, а для ReadLn – только #13 и #10. Например, при чтении информации в строковые переменные String или PChar заносятся очередные символы до #13 и #10.
Для подготовки текстовых файлов можно использовать не только программную среду Delphi, но и любые простые редакторы.
При записи информации необходимо для файла задать явно режим записи. Для текстовых файлов режим записи задается одновременно с режимом создания нового файла. При этом используется процедура Rewrite(<ф.п.>). Если файл, указанный в соответствующей процедуре AssignFile существует, то он уничтожается и создаётся новый. Запись информации в файл осуществляется процедурами Write(<ф.п.>, <список>) или WriteLn(<ф.п.>, <список>). Write записывает очередной элемент строки, WriteLn – записывает строку вместе с #13 и #10. В отличие от процедур чтения, в списке можно указывать не только переменные, но и выражения. Если элементы числовые, то в списке необходимо явно предусматривать разделители между этими элементами. Например,
WriteLn(T,‘число а=’,а,’ ’,‘число b=’,b);
ТИПИЗИРОВАННЫЕ ФАЙЛЫ
Файловая переменная для этого типа объявляется следующим образом: Var F : file of <тип элементов>;.
Тип элементов может быть любым, за исключением файлового типа и указательного. Например, Var F : file of Double;.
Как и в случае текстовых файлов, для работы с типизированными файлами необходимо файловую переменную связать с конкретным файлом, затем указать режим работы с этим файлом и по окончании закрыть его, например,
AssignFile(F, ‘c:\a.dat’);
Reset(F); {или Rewrite(F)}
. . . . . .
CloseFile(F);
Процедура Rewrite, как и в случае текстовых файлов, открывает новый типизированный файл для записи информации. Однако процедура Reset работает не так, как с текстовыми файлами, - она устанавливает доступ и на чтение и на запись информации. Чтение и запись осуществляется следующими процедурами:
Read(<ф.п.>, <список>);
Write(<ф.п.>, <список>);
Так как данный файл является файлом прямого доступа, можно устанавливать файловый указатель на любую запись файла. Для этой цели используется процедура
Seek(<ф.п.>, <номер записи>); {отсчет от 0}
Найденную запись можно прочитать или снова перезаписать. В отличие от текстовых файлов, при записи информации в типизированный файл нельзя использовать в процедуре Write выражения.
ФАЙЛЫ БЕЗ ТИПА
В данном случае файловая переменная указывается так:
Var F : file;
Связывание файловой переменной с конкретным файлом и закрытие файла осуществляется так же, как и для типизированных файлов. Однако задание режима работы с файлом отличается от аналогичной операции, применяемой к типизированному файлу:
Reset(<ф.п.>, Size);
Rewrite(<ф.п.>, Size);
Добавляется дополнительный параметр - Size – размер элементов в файле. Величину Size можно устанавливать равной 1. Можно не указывать Size, тогда система по умолчанию примет величину 128. Чтение и запись производятся процедурами:
BlockRead(<ф.п.>, Buffer, N, Result);
BlockWrite(<ф.п.>, Buffer, N, Result);
Здесь Buffer обычно задаётся описанием Array … of Char или Array … of Byte; N – количество элементов, которое требуется прочитать или записать; Result– конкретное количество элементов, которое прочиталось или записалось.
Если пользователь знает, какая информация записана в файле, то можно задавать конкретный размер записи. Например, если необходимо работать со структурами данных, то используя функцию SizeOf, можно определить размер записи, кратный полученному с помощью SizeOf числу. Использование процедур BlockReadиBlockWriteв этом случае значительно ускорят работу с файлами.