try {создание формы}
application. CreateForm(tForm1,Form1);
application. Run;
except
on E:Exception do
begin messageBox(E. message,’Y’,mb_Ok);
E. message:='Ошибка в программе';
Raise;
end{/do};
end{/except};
Замечание: исключения, в отличие от других типов, принято именовать с буквы "E", а не с "t".
Некоторые важнейшие типы исключений:
EMathError — все математические ошибки; EInOutError — все ошибки ввода-вывода; EConvertError — ошибки преобразования типов; EOutOfMemory — нехватка памяти; EPrinter — ошибка работы с принтером; EAbort — вызывается программно вызовом процедуры Abort; не делает ничего и предназначена для обработки программистом для нужд текущей программы.Блоки защиты ресурсов и обработчики исключительных ситуаций могут быть вложенными. Например, выделение ресурсов можно производить так:
try {1}
allocateResource1;
try {2}
allocateResource2;
UseResources;
finally{2}
FreeResource2;
end{/try2};
finally{1}
FreeResource1;
end{/try1};
Другой вариант решения этой проблемы:
const Ok1,Ok2:Boolean:=False;
...
try
AllocateResource1;
Ok1:=True;
AllocateResource2;
Ok2:=True;
except
on Exception do
begin
if Ok2 then
begin
FreeResource2;
if Ok1 then FreeResource1;
end{/if};
end{/do};
end{/except};
Можно вкладывать друг в друга обработчики исключений:
procedure ECheck(var A, B,Y, Z:Real);
var X:Real;
begin
try{1}
X:=(-B*X+sqrt(B*B-4*A*C))/(2*A);
try{2}
Z:=X/sqrt(A*Y*Y-7*B/A/(X-3sqrt(B)));
except{2}
on EMathError do
application. MessageBox('ошибка в вычислении Z',Y, mb_Ok);
end{/except2};
except{1}
on EMathError do
application. MessageBox('ошибка в вычислении корня
уравнения ',Y, mb_Ok);
end{/except1};
end{/ECheck};
Для создания собственной исключительной ситуации в случае, когда обычные исключения не возбуждаются, надо описать соответствующий класс, например:
EWrongPassword=
class(Exception)
end;
В теле класса можно ничего не описывать! В реализации программы в нужный момент надо инициализировать исключение с помощью конструктора, и тогда обработчик исключений сможет его обработать.
Например:
var S, S1:String;
try
S:=...
...
myReadPassword(S1);
if(S1<>S)then EWrongPassword. Create('Wrong password!');
...
except
on EWrongPassword do...;
end{/except};
...
Создание и обработка исключительных ситуаций позволяют структурным способом решить проблемы, в которых в обычном PASCAL приходилось использовать метки и оператор goto, а также ставить огромное число проверок на допустимость присваиваний и математических операций. Мало того, что эти проверки резко замедляли работу программы — не было гарантии, что они достаточны, и что во время работы программы не возникнет "вылет" из-за возникновения непредусмотренной исключительной ситуации. В Object Pascal, как мы видим, эта проблема решена кардинально.
Замечание: в "С-образных" языках С++, JavaScript и Java также имеется обработка исключительных ситуаций, построенная по варианту try...catch..., аналогичная try...except... для Object Pascal (слово "catch" означает "перехватить"). Существенное отличие — после обработки одного исключения производится переход к следующему, если не поставить оператор break, такая логика работы очень часто приводит к ошибке, которую можно назвать "забытый break ".
4.14. Специальные средства для работы с MS Windows: сообщения.
Для обработки сообщений Windows в Delphi существует механизм динамических методов, называемых сообщениями. Они должны быть описаны в классе как процедуры, имеющие один параметр, передаваемый по имени (через var). После описания заголовка через ";" должно идти зарезервированное слово message, после которого идет индекс — идентификатор сообщения. Описание параметра, передаваемого в процедуру через var, произвольно (в первоначальной версии Delphi параметр должен был описываться как переменная соответствующего для message типа : tWM_Size, tWM_Move, и т. д.):
type
tMyControl1=
class(tWinControl)
procedure WMSize(var message:tWMSize);message WM_Size;
{начальный вариант синтаксиса}
end;
tMyControl2=
class(tMyControl1)
procedure Resize(var Info);message WM_Size; {так тоже можно}
end;
В модуле Messages описаны обработчики практически всех необходимых сообщений Windows. Каждый обработчик имеет идентификатор — целочисленную константу. Например, WM_Size — идентификатор сообщения об изменении размера экранной формы, WM_Move — идентификатор сообщения о ее перемещении и т. д.
В обработчиках сообщений можно вызвать прародительский метод с использованием только одного слова inherited, без указания его имени: он находится автоматически по индексу.
Самый общий обработчик — метод DefaultHandler, описанный в классе tObject. При обработке сообщения обычно надо вызвать в конце обработчик для прародителя:
procedure MyMsgHandler(var message);message WM_command;
begin
MyProcessing; {некая процедура обработки сообщения}
inherited; {в отличии от конструктора, вызов в самом конце}
end;
При получении объектом от операционной системы Windows сообщения описанного типа (идентификация сообщений происходит автоматически по индексам) вызывается соответствующий обработчик. В описанном выше примере это MyMsgHandler.
Однако обычно нет необходимости обрабатывать сообщения Windows, так как имеется механизм делегирования событий, о котором сейчас пойдет речь.
При необходимости обработки сообщений в обработчике события (см. следующий параграф) надо вызвать метод application. processMessages.
4.15. События и их делегирование. Обработка событий.
События — это свойства процедурного типа. Их название принято начинать с префикса "on". Для описания события некого типа (как описать новый тип события будет рассказано далее) в объекте надо описать поле того же типа, что и свойство. Реально это поле служит указателем на процедуру обработчика события. Кроме того, надо описать собственно свойство:
fOnMyEvent:tMyEvent;
property OnMyEvent:tMyEvent
read fOnMyEvent
write fOnMyEvent;
Тут поле fOnMyEvent является ссылкой на процедуру, с помощью которой осуществляется обработка события. Это поле доступно по чтению и записи! Присваивание свойству значения — это присваивание полю fOnMyEvent указателя на метод, который будет вызываться при наступлении события. Чтение — это метод. Эти методы называются обработчиками событий. Если никакой обработчик не присвоен полю-указателю, то там хранится значение notAssigned.
Пример:
присваивание
application. onActivate:=MyMethod; {MyMethod — имя некой процедуры – обработчика события}
означает, что при запуске приложения будет сначала выполнена процедура MyMethod.
Возможность такого рода действий связана с тем, что указание имени процедуры, функции, массива, объекта в Delphi — это указание соответствующего адреса, а он в принципе может быть переприсвоен. Таким образом, события описываются как свойства, доступные по записи, и при выполнении условия совместимости по типам их обработчики могут быть переприсвоены (говорят, что события делегированы).
Общим для описания типа "событие" является первый параметр Sender типа tObject и ключевая фраза of object после описания типа. Ниже приведен пример задания и использования определенного пользователем типа события tMyEvent:
type
{tNotifyEvent=procedure(Sender:tObject)of object;}
{предопределенное простейшее событие}
tMyEvent=procedure(Sender:tObject;var aMyVar:tMyVar) of object;
tObj1=
class
fOnMyEvent:tMyEvent;
property onMyEvent:tMyEvent
read fOnMyEvent
write fOnMyEvent;
end;
tObj2=
class
procedure MyEventProcessing1(Sender:tObject;
var aMyVar:tMyVar);
procedure MyEventProcessing2(Sender:tObject;
var aMyVar:tMyVar);
end;
...
var aObj1:tObj1;
aObj2:tObj2;
myKey:Boolean;
begin
aObj1:=tObj1.Create;
aObj2:=tObj2.Create;
...
if MyKey
then
aObj1.onMyEvent:=aObj2.MyEventProcessing1
else
aObj1.onMyEvent:=aObj2.MyEventProcessing2;
...
end.
При делегировании можно присваивать методы других классов! Даже не являющихся потомком и прародителем! Но при этом должно быть полное соответствие списков параметров обработчиков событий со списком параметров процедурного типа события.
4.16. Методы класса и указатели на класс.
Некоторые методы бывает нужно вызывать без создания экземпляра класса (например, для получения информации о имени класса, размере экземпляра класса и т. п.). Такие методы называются методами класса - в C++ и Java они называются статистическими методами (не путать со статистическими методами в смысле TP и Delphi!). Методы класса имеют перед словами procedure или function ключевое слово class (за исключением конструкторов, которые также являются методами класса, но для которых синтаксис, как мы знаем, другой):
type
tMyObj=
class
class function MyGetSize:String;
end;
var aMyObj:tMyObj;
begin
...
Label1.caption:=tMyObj. MyGetSize; {вызов метода класса tMyObj}
aMyObj:=tMyObj. Create; {вызов другого метода класса tMyObj}
Label2.caption:=aMyObj. MyGetSize; {вызов метода класса с
экземпляром класса}
...
end;
Возможно описание указателя на класс с помощью ключевой фразы class of. Это иногда требуется в программах, использующих сложную иерархию объектов, для унифицированного динамического создания, копирования и уничтожения объектов, принадлежащих разным классам. В модуле SysUtils указатель на tObject описан так:
type tObject=class;
tClass=class of tObject;
Имеются следующие важнейшие стандартные функции классов, определенные в tObject:
class function ClassName:string — возвращает имя класса, вызвавшего объект; class function ClassParent:tClass — возвращает указатель на класс прародителя; function ClassType:tClass — возвращает указатель на класс вызвавшего объекта; class function ClassInfo:Pointer — возвращает указатель на структуру (запись), содержащую информацию о классе.Также имеется ряд других стандартных функций классов.
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |


