Наше приложение вполне работоспособно, пока пользователь выполняет "правильные" действия: вводит числа в разрешенном формате, производит разрешенные операции, например, не допускает деления на ноль, вычислений с недопустимо большими значениями, извлечения корня из отрицательного числа и т.п. Однако, стоит ему выйти за пределы допустимых действий, и выполнение программы будет прервано. В этом можно убедиться, загрузив приложение и нажав кнопку . Поскольку в окно ввода чисел первоначально мы помещаем 0, то программа завершиться аварийно с сообщением, показанным на Рис. 5.2.:
Окно сообщения об ошибке времени исполнения (Проект Project2.exe вызвал исключительную ситуацию класса EZeroDivide c сообщением 'Деление на ноль с плавающей точкой').
Это сообщение выводит визуальная среда Delphi. Для возврата в нее необходимо завершить проект, нажав комбинацию клавиш Ctrl-F2.
Наша задача состоит в том, чтобы максимально защитить приложение от результатов возникновения ИС. Для этого воспользуемся обработчиками ИС, принадлежащих иерархии классов Exception, а также оператором try… except. Надо сказать, что среда Delphi по умолчанию перехватывает все ИС, выводит собственное сообщение и останавливает выполнение проекта. Чтобы этого избежать снимем флажок "Stop On Delphi Exceptions" в диалоге Tools – Debugger Options… главного меню Delphi
Флажок перехвата ИС в настройках Delphi
Теперь, если мы не предусмотрим иного, обработка ИС будет выполняться стандартным обработчиком подсистемы времени исполнения Delphi.
Создадим собственную систему обработки ИС.
Начнем с процедуры обработки нажатия клавиш арифметических операций. Здесь возможно возникновение ИС, связанной
1) со вводом неправильного числа с плавающей точкой (EConvertError) и
2) со вводом слишком большого числа (EOverFlow – переполнение с плавающей точкой). В секцию try оператора обработки ИС поместим критичный с точки зрения возникновения ИС оператор
Value1:= StrToFloat(ValueEdit.text);
а в секции except предусмотрим два последовательных блока on…do, обрабатывающих обе возможные ИС:
procedure TForm1.SpeedButton1Click(Sender: TObject);
Begin
if ((Sender As TSpeedButton).Tag = 1) and (ValueEdit.SelStart = 0) then
Begin
ValueEdit.Text:= '-'+ValueEdit.text;
ValueEdit.SelStart:= 1;
Exit;
end;
Try
Value1:= StrToFloat(ValueEdit.text);
Except
on EOverFlow do
Begin
Showmessage('Переполнение!');
Value1:= 0;
ValueEdit.Text:= FloatToStr(Value1);
exit;
end;
on EConvertError do
Begin
Showmessage('Неверное число!');
Value1:= 0;
ValueEdit.Text:= FloatToStr(Value1);
exit;
end;
end;
SpeedButton16Click(Sender);
Oper:= (Sender As TSpeedButton).tag;
end;
Результатом обработки обоих ИС будет вывод соответствующего сообщения, присваивание первому операнду значения 0, вывод этого значения в текстовом блоке и досрочный выход из процедуры.
Займемся обработкой ИС, которые могут возникнуть при нажатии кнопки . Здесь могут возникнуть ИС:
1) ввод неправильного числа в качестве значения второго операнда (EConvertError);
2) переполнение с плавающей точкой (EOverFlow);
3) деление на ноль с плавающей точкой (EZeroDivide). (Возможна также ИС EUnderFlow – слишком маленькое число с плавающей точкой, "машинный ноль", однако, как правило, эта ИС некритична и не вызывает остановки программы.)
Обработаем две первых ИС во вложенных блоках try … except, а последнюю – при выполнении операции деления, где она может возникнуть.
Преобразуем код обработчика события OnClick кнопки :
procedure TForm1.SpeedButton18Click(Sender: TObject);
Begin
Try
Value2:= StrToFloat(ValueEdit.Text);
Try
case Oper of
0: Value1:= Value1 + Value2;
1: Value1:= Value1 - Value2;
2: Value1:= Value1 * Value2;
3:
Begin
Try
Value1:= Value1 / Value2;
Except
on EZeroDivide do
begin
Showmessage('Деление на ноль!');
Exit;
end;
end;
end;
end;
Except
on EOverFlow do
Begin
Showmessage('Переполнение!');
exit;
end;
end;
Except
on EConvertError do
Begin
Showmessage('Неверное число!');
Value2:= 0;
ValueEdit.Text:= FloatToStr(Value2);
exit
end;
end;
ValueEdit.Text:= FloatToStr(Value1);
end;
Напишем теперь обработчик ИС, которые могут возникнуть при нажатии клавиши . Здесь могут возникнуть две ИС:
1) неправильное число с плавающей точкой и
2) корень из отрицательного числа (EInvalidOp – неправильная операция с плавающей точкой, либо неверная инструкция процессора). Преобразованный код обработчика события OnClick для этой кнопки приведен ниже.
procedure TForm1.SpeedButton17Click(Sender: TObject);
Begin
Try
Value1:= StrToFloat(ValueEdit.text);
Except
on EConvertError do
Begin
Showmessage('Неверное число!');
Value1:= 0;
SpeedButton16Click(Sender);
Exit;
end;
end;
Try
Value1:= sqrt(Value1);
Except
on EInvalidOp do
Begin
Showmessage('Корень из отрицательного числа!');
Exit;
End
end;
ValueEdit.Text:= FloatToStr(Value1);
end;
Задание. Напишите аналогичные обработчики событий OnClick для кнопок и
.
Указание. При обработке события OnClick для кнопки могут возникнуть ИС
1) неправильное число с плавающей точкой;
2) переполнение с плавающей точкой.
При обработке события OnClick для кнопки . могут возникнуть ИС
1) неправильное число с плавающей точкой;
2) переполнение с плавающей точкой; 3) деление на ноль.
Мы создали все обработчики ИС, которые могут возникнуть в результате выполнения нашего приложения, за исключением ситуации, когда в локализованной ("русской") версии ОС Windows в десятичной записи числа вместо точки установлена запятая. В этом случае в нашей программе ввод любого числа с дробной частью будет вызывать ИС EConvertError. Для того, чтобы этого избежать, при создании формы можно проверить какой символ используется в качестве разделителя и использовать именно его:
procedure TForm1.FormCreate(Sender: TObject);
Begin
Try
ValueEdit.Text:= '1.2';
Value1:= StrToFloat(ValueEdit.Text);
Except
on EConvertError do SpeedButton14.caption:= ',';
end;
value1:= 0;
value2:= 0;
ValueEdit.Text:= FloatToStr(Value1);
Oper:= -1;
end;
В процедуре при обнаружении ИС заголовок кнопки с десятичной точкой меняется на запятую.
Задание. Замените операцию на
(x в степени y). Напишите соответствующий обработчик события и обеспечьте его обработкой возможных ИС.
Указания. 1) xy = exp(y*ln(x))
2) Данная операция двуместная, поэтому ее нужно обрабатывать в процедуре SpeedButton18Click кнопки .
3) Возможные ИС: переполнение, неправильная операция ln.
Результаты работы
В результате выполнения лабораторной работы студент должен продемонстрировать преподавателю готовый проект, содержащий обработку исключительной ситуации, файл формы и исходный код модуля.