Показаны сообщения с ярлыком Label. Показать все сообщения
Показаны сообщения с ярлыком Label. Показать все сообщения

пятница, 23 марта 2012 г.

Урок 38. Обработчик ошибок

Во времена фортрана меня учили обходиться без оператора Goto. Использование оператора безусловного перехода считалось моветоном равным по грешности полному отсутствию комментариев в программе.

А посему, считаю, что каждый вправе придумать свой алгоритм обработчика ошибок... Я лишь покажу один из возможных вариантов.

Первый вопрос, который я предвижу от слабо посвященных: "А зачем?"
Действительно, пишешь задачу, как "честная кнопка", пытаешься ничего не упустить, все предусмотреть, собственное творчество, как правило, себе нравится, и не вызывает сомнений правильность его алгоритма... И все же! Если задачка небольшая - все просто и прозрачно. Но, если алгоритм сложен... как говорят "глаз замыливается", перестает находить узкие места. К тому же накладывается человеческий фактор: откуда Вам было знать, что пользователь не введет значение в поле и нажмет "Enter"?.. В этот момент Ваша программа напугает его каким-нибудь англоязычным сообщением да еще и с пиктограммой "Error"... А, если Вы помните, я с самого начала просил Вас уважать пользователя и заказчика. Стоит ли доводить ситуацию до общения с плохо вменяемым пиплом?! Если Вы не хотите общаться с человеком, у которого от испуга вытаращены глаза и трясутся руки, нужно научиться предугадывать (перехватывать) ошибки и выдавать на экран сообщения на родном для пользователя языке, желательно с номером Вашего телефона... Это и есть часть понятия "дружественный интерфейс".

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

где и когда нужен обработчик ошибок?

Стоит ли, на эту тему рыться в учебниках? И "да", и "нет". Почему? Программа, о которой в настоящий момент идет речь ("Расходы"), работает с базой данных, а найти в книжках этот материал - ой как не просто, поскольку большую часть книжного пространства авторы отводят, как правило, обучению работе с базой данных (создание, подключение, запросы и т.п.). Можно долго и упорно рыться в интернете, гуглить яндекс и задавать вопросы на форумах - в конце концов, Вы соберете нужную инфу, но упустите время...

Я же со своей стороны предлагаю почаще спрашивать себя "А вдруг?"
А вдруг сервер не сохранит запись?
А вдруг пользователь не введет допустимое значение и что-нибудь нажмет, закроет окно и т.п.
А вдруг такая запись уже есть в базе данных?
А вдруг...

Чем большим количеством подобных вопросов Вы себя озадачите, тем меньше вероятность того, что Ваша программа в руках незадачливого пользователя перейдет в состояние "Не отвечает".

Наиболее общая схема обработчика ошибок выглядит примерно так:

  • Объявление необходимых переменных и присвоение им стартовых значений.
  • Выполнение основного алгоритма, в процессе которого проверяются возможные условия возникновения ошибок
  • Обработка ошибок
  • Выдача сообщения оператору
Я предлагаю вернуться к предыдущему уроку и на примере описанных в нем процедур "сочинить" несложный обработчик ошибок.

Добавьте в объявление переменных в процедуре SetLang() еще парочку:

Var
  ini: TIniFile;
  ErrKod: integer;
  ErrMsg: String;

а так же - объявление метки:

Label
  ErrLabel;

и стартовые значения:


begin

  ErrKod:=0;                                    // Это значение при отсутствии ошибок
  ErrMsg:= 'Операция завершена успешно';

Настройте заранее (в начале процедуры) компонент, выдающий сообщения:


  MyMessenger.TitleString:='Ошибка...';
  MyMessenger.MessageType:=mtError;
  MyMessenger.Buttons:=[mbOK];


Затем - напишите проверку наличия файла языковой поддержки:


  If Not FileExists(GetCurrentDir + '\'+Lang)
  then
  begin
    ErrKod:=1;
    ErrMsg:='При попытке открытия файла языковой настройки произошла ошибка';
  end;


Почему именно здесь нужно предусмотреть какие-то действия? А вдруг в файле настроек указан несуществующий файл? Или его кто-то с диска того... нечаянно стер...

Следом должна идти проверка на наличие ошибок:


  if ErrKod>0
  then
    Goto ErrLabel;


...


Если в результате этой проверки выясняется, что код ошибки стал больше нуля (а проверок может быть несколько и код ошибки может принимать десяток разных значений), то оператор безусловного перехода, минуя основную ветвь алгоритма, отправит нас на метку ErrLabel, после которой и написан нехитрый в данном случае обработчик ошибок:


...


ErrLabel:


    MyMessenger.MessageString:=ErrMsg;
    MyMessenger.ShowMessage;


end;        // Процедуры


Давайте нашалим: переименуем файл Rus.lng, например в Rus1.lng, чтоб программа его уж точно не нашла.

Тогда при старте Rashod.exe будет произведена попытка настроить интерфейс приложения с помощью указанного в файле настроек Rashod.ini, в секции [Constants], в переменной LangFileName файла Rus.lng, которого в рабочем каталоге нет. Сработает обработчик ошибки, и на экране будет выведено придуманное нами сообщение:


В данной ситуации больше никаких мер принимать не нужно, так как интерфейс программы получит те надписи и пункты меню, которые были заложены в него при проектировании. Я еще раз подчеркиваю, что я лишь показываю как, а Вам уже думать, где это применять.

Верните переименованному файлу его законное название и запустите программу еще раз.
Вы получите еще одно сообщение:


не корректное по оформлению и неуместное по сути (если ошибок нет, нужно ли в данном случае вообще выводить какое-то сообщение?!).

Давайте поправим ситуацию:

ErrLabel:

  Case ErrKod of
    0:                               // Ошибок нет
    else
    begin
      MyMessenger.MessageString:=ErrMsg;
      MyMessenger.ShowMessage;
    end;

  End;

end;        // Процедуры


Теперь в отсутствии ошибок программа загрузится в штатном режиме, т.е. без лишних сообщений.

В заключение хочу заметить, что обработчики ошибок при работе с базой данных чаще всего нужны при выполнении оператора Post, посылающего данные в источник.