Мансуров. Основы программирования в среде Lazarus. 2010
.pdfГлава 6 Программирование приложений с графическим интерфейсом
____________________________________________________________________
но возникновение исключений. После except следуют операторы, которые образуют секцию обработки исключений. Признаком конца секции служит ключевое слово end. Внутри секции программист указывает классы исключе-
ний (говорят еще типы исключений) после слова on, а затем после ключевого слова do оператор обработки исключения, причем оператор может быть со-
ставным. После необязательного else следуют операторы обработки исклю-
чений, не вошедшие в перечень on. Если программисту нужно только устано-
вить сам факт исключения, независимо от типа, то он может просто записать обработчик исключения после слова except.
Вторая конструкция имеет вид:
try
<Потенциально "опасные" операторы, при выполнении которых могут возникнуть исключительные ситуации >
finally
<операторы, которые должны быть выполнены в любом случае, незави-
симо от того, произошло исключение или нет >
end;
В чем их различие? В конструкции try..except если при выполнении операторов секции try возникло исключение, то управление передается в сек-
цию except, где и происходит обработка исключения. Если же исключения не произошло, то операторы блока except просто пропускаются. В конструкции try..finally операторы будут выполнены независимо от того, произошло исключение или нет.
Рассмотрим пример:
try
num:=StrToInt(Stroka);
521
6.3 Визуальное программирование в среде Lazarus
____________________________________________________________________
except
on EConvertError do
ShowMessage('Ошибка преобразования строки в целое число');
end;
Здесь сообщение будет выведено только в том случае, когда невозможно преобразование строки символов в целое число, то есть когда возникнет ис-
ключение EConvertError.
Конструкции try..except и try..finally могут быть вложены друг в друга на неограниченную глубину. Рассмотрим реализацию примера с файлом.
Procedure Test; var
F: TextFile; number: integer; s: string;
begin
AssignFile(F, 'Data.txt');
Rewrite(F);
s:= '12#4'; |
// В файл намеренно записывается |
|
Writeln(F, s); |
// ошибочная строка символов |
|
Reset(F); |
|
|
try |
// начало секции (блока) try..except |
|
Readln(F, s); |
|
|
try |
// начало секции try..finally |
number:= StrToInt(s);
finally
CloseFile(F); // эти два оператора будут выполнены
522
Глава 6 Программирование приложений с графическим интерфейсом
____________________________________________________________________
DeleteFile('Data.txt'); // в любом случае
end; // конец секции try..finally
except
on EConvertError do
ShowMessage('Ошибка преобразования'); end; // конец секции try..except
end;
Вернемся к примеру, в котором осуществляется ввод двух целых чисел и выполняются четыре арифметических действия (сложение, вычитание, умно-
жение и деление нацело), рис. 6.30. Модифицируем программу, добавив в него обработку исключений. Перепишите обработчики события OnKeyPress для
LabeledEdit1 и событий OnClick кнопок SpeedButton1, SpeedButton2, SpeedButton3 и SpeedButton4 в виде:
procedure TForm1.LabeledEdit1KeyPress(Sender: TObject; var Key: char);
begin
if Key = #13 then begin
try StrToInt(LabeledEdit1.Text);
except
on EConvertError do begin
ShowMessage('Ошибка преобразования! Вероятно, ' +
'Вы ошиблись при вводе числа');
exit;
end;
523
6.3 Визуальное программирование в среде Lazarus
____________________________________________________________________
end;
LabeledEdit2.SetFocus; SpeedButton1.Down:= false; SpeedButton2.Down:= false; SpeedButton3.Down:= false; SpeedButton4.Down:= false; exit;
end;
end;
procedure TForm1.SpeedButton1Click(Sender: TObject); begin
try LabeledEdit3.Text:=IntToStr(StrToInt(LabeledEdit1.Text)
+ StrToInt(LabeledEdit2.Text));
except
on EConvertError do begin
ShowMessage('Ошибка преобразования! Вероятно, ' + 'Вы ошиблись при вводе второго числа');
exit;
end;
end;
StatusBar1.SimpleText:= 'Сложение';
LabeledEdit1.SetFocus;
LabeledEdit1.SelectAll;
end;
procedure TForm1.SpeedButton2Click(Sender: TObject);
524
Глава 6 Программирование приложений с графическим интерфейсом
____________________________________________________________________
begin try
LabeledEdit3.Text:=IntToStr(StrToInt(LabeledEdit1.Text)
- StrToInt(LabeledEdit2.Text));
except
on EConvertError do begin
ShowMessage('Ошибка преобразования! Вероятно, ' + 'Вы ошиблись при вводе второго числа');
exit;
end;
end;
StatusBar1.SimpleText:= 'Вычитание';
LabeledEdit1.SetFocus;
LabeledEdit1.SelectAll;
end;
procedure TForm1.SpeedButton3Click(Sender: TObject); begin
try LabeledEdit3.Text:=IntToStr(StrToInt(LabeledEdit1.Text)
* StrToInt(LabeledEdit2.Text));
except
on EConvertError do begin
ShowMessage('Ошибка преобразования! Вероятно, ' +
'Вы ошиблись при вводе второго числа');
exit;
end;
525
6.3 Визуальное программирование в среде Lazarus
____________________________________________________________________
end;
StatusBar1.SimpleText:= 'Умножение';
LabeledEdit1.SetFocus;
LabeledEdit1.SelectAll;
end;
procedure TForm1.SpeedButton4Click(Sender: TObject); begin
try LabeledEdit3.Text:=IntToStr(StrToInt(LabeledEdit1.Text)
div StrToInt(LabeledEdit2.Text));
except
on EConvertError do begin
ShowMessage('Ошибка преобразования! Вероятно, ' + 'Вы ошиблись при вводе второго числа');
exit;
end;
on EDivByZero do begin
ShowMessage('Ошибка! Произошло деление на ноль. Вероятно, ' + 'Вы ошиблись при вводе второго числа');
exit;
end;
end;
StatusBar1.SimpleText:= 'Деление нацело';
LabeledEdit1.SetFocus;
LabeledEdit1.SelectAll;
end;
526
Глава 6 Программирование приложений с графическим интерфейсом
____________________________________________________________________
Теперь при вводе недопустимого символа для целого числа, а также при вводе числа 0 в качестве второго операнда программа перехватывает исключе-
ния и реагирует соответствующим образом.
Имейте в виду, если вы запускаете программу из среды Lazarus, то исклю-
чения будет перехватывать отладчик. Поэтому лучше запускать программу из командной строки или в настройках окружения для отладчика добавьте нужные вам типы исключений в список игнорирования.
Обработку исключений вполне можно применять и в консольных прило-
жениях. Вспомним программу из 2.1.14. Организуем контроль ввода данных,
используя механизм исключений.
program int_operations_control; {$mode objfpc}{$H+}
uses
CRT, FileUtil, SysUtils; var
A, B, C: integer; begin
writeln(UTF8ToConsole('Введите два числа')); readln(A, B);
writeln('A= ', A, ' B= ', B); C:= A + B;
writeln(UTF8ToConsole('Демонстрация сложения, C= '), C); C:= A * B;
writeln(UTF8ToConsole('Демонстрация умножения, C= '), C); try
C:= A div B;
writeln(UTF8ToConsole('Демонстрация деления нацело, C= '),
C);
527
6.3 Визуальное программирование в среде Lazarus
____________________________________________________________________
except
on EDivByZero do begin
writeln(UTF8ToConsole('Ошибка!! Деление на ноль.')); writeln(UTF8ToConsole('Нажмите любую клавишу')); readkey;
exit;
end;
end;
C:= A mod B;
writeln(UTF8ToConsole('Остаток от деления, C= '), C); C:= A - B;
writeln(UTF8ToConsole('Демонстрация вычитания, C= '), C); writeln(UTF8ToConsole('Нажмите любую клавишу')); readkey;
end.
Сравните эту программу с программой из 2.1.25.
Контроль и обработку ошибок с применением механизма исключений удобнее использовать, когда работа программы уже не зависит от действий пользователя, т.е. все необходимые данные от пользователя уже получены,
программа перешла непосредственно к обработке данных – идут вычисления,
происходит чтение и запись в файлы, обращения к различным внешним уст-
ройствам и т.д. На этапе же ввода данных, когда пользователь в режиме диало-
га вводит какие-то данные с клавиатуры, удобнее использовать другой способ контроля. Поскольку обработка исключений происходит после завершения ввода пользователем, то есть этим происходит только констатация факта, что ошибка пользователем уже совершена. Приходится организовывать повторный ввод, причем с того места, где пользователь ошибся. А это приведет к усложне-
528
Глава 6 Программирование приложений с графическим интерфейсом
____________________________________________________________________
нию кода. Гораздо разумнее и эффективней при вводе данных просто не давать пользователю совершить ошибку. Например, если пользователь должен вво-
дить только целые числа, проще контролировать введенные пользователем символы и, если будет попытка ввести недопустимый для целых чисел символ,
просто этот символ игнорировать.
Для этого удобнее использовать другую разновидность компонента TEdit
– TMaskEdit из страницы Additional.
6.3.7.1. Компонент TMaskEdit
В этом компоненте имеется свойство EditMask, с помощью которого можно задать маску ввода. Маска это некий шаблон, задающий какие символы может вводить пользователь в окне ввода. Недопустимые символы игнориру-
ются. Маска состоит из трех частей, между которыми ставится точка с запятой
(;). В первой части маски – шаблоне записываются символы (табл. 6.2), кото-
рые указывают какие символы можно вводить в каждой позиции.
Таблица 6.2
Символ |
Шаблон ввода |
Означает, что в EditText недостающие символы предваряются
!пробелами. В случае отсутствия символа пробелы размещаются в конце.
0 Означает, что в данной позиции должна быть цифра.
9 Означает, что в данной позиции может быть цифра или ничего.
#Означает, что в данной позиции может быть цифра, знак « + », знак «-» или ничего.
Далее через точку с запятой (;) записывается 1 или 0 в зависимости от того,
надо или нет, чтобы символы, добавляемые маской, включались в свойство
Text компонента. В третьей части маски указывается символ-заполнитель, ис-
пользуемый для обозначения позиций, в которых еще не осуществлен ввод. Ус-
тановить нужную маску можно прямо в свойстве EditMask, введя необходи-
мые символы маски или в редакторе масок, открыть который можно нажав
529
6.3 Визуальное программирование в среде Lazarus
____________________________________________________________________
кнопку с троеточием, рис. 6.33.
Рис. 6.33. Окно редактора масок
Прочитать результат ввода можно или в свойстве Text, которое, в зависи-
мости от вида второй части маски, включает или не включает в себя символы маски, или в свойстве EditText, содержащем введенный текст вместе с сим-
волами маски.
Итак, давайте применим для нашего примера компонент TMaskEdit.
Удалите из формы LabeledEdit1 и LabeledEdit2. Перенесите на их ме-
сто два компонента TMaskEdit. Также вставьте в форму два компонента
TLabel. В общем, восстановите внешний вид формы как на рисунке 6.30.
Установите следующие свойства MaskEdit1:
AutoSelect = true
EditMask = #9999;0;
TabOrder = 0
свойство Text оставьте пустым.
В качестве символа заполнителя в окошке "Символы для пробелов" в ре-
дакторе масок введите пробел вместо знака подчеркивания.
Установите свойства MaskEdit2:
530