при попытке сохранения пустой строчки происходит ошибка...
написали "Апрель", но не ввели номер месяца - другая...
Если пользователь - Вы сам, то беды большой нет, поскольку Вы знаете в чем тут дело и как поправить. Но я стараюсь как можно чаще давать понять моему читателю, что пугать неподготовленного пользователя служебными сообщениями есть моветон. Как плохой манерой является и исполнение маневров, подобных тем, что исполняют в МТС.
Чтобы избежать этих мелких неприятностей, нужно в момент добавления записи в соответствующую таблицу, присвоить полям стартовые значения.
Найдите на форме компонент ADOTABLEMOS и напишите обработчик свойства AfterInsert:
procedure TMainFrm.ADOTableMOsAfterInsert(DataSet: TDataSet);
var
year, month, day: Word;
monthName:array[1..12] of string[8]; // Объявление одномерного массива фиксированного размера
begin
// Присвоение начальных значений элементам массива
monthName[1]:='Январь';
monthName[2]:='Февраль';
monthName[3]:='Март';
monthName[4]:='Апрель';
monthName[5]:='Май';
monthName[6]:='Июнь';
monthName[7]:='Июль';
monthName[8]:='Август';
monthName[9]:='Сентябрь';
monthName[10]:='Октябрь';
monthName[11]:='Ноябрь';
monthName[12]:='Декабрь';
// Декодирование текущей даты Date() функцией DecodeDate(). Результат - в переменных year, month, day
DecodeDate(Date(), year, month, day);
// Добавление значений по умолчанию в список мемориальных ордеров
ADOTableMOs.FieldByName('Mes').Value:= IntToStr(month);
ADOTableMOs.FieldByName('Name').Value:= monthName[month]; // Значение из массива по номеру месяца
end;
Теперь при добавлении новой записи программа поможет оператору:
Вы можете смело продолжить работу, а я попутно хочу заметить
1. Массив monthName можно объявить не в этой процедуре, а выше - на уровне модуля, сделав его не локальным, а глобальным по отношению к данному модулю, если его значения необходимы в других процедурах. Тогда объявление массива можно было бы совместить с присвоением его элементам значений:
monthName: array[1..12] of String[8]=
('Январь','Февраль','Март',и т.д. до,'Декабрь');
2. Алгоритм "угадывания" названия месяца по его номеру можно вынести в DLL в виде отдельной функции, так как он может понадобится не только в этой программе, но и в других.
3. На основе этого несложного алгоритма можно сделать компонент, на входе которого будет номер месяца, а на выходе - его название.
Все хорошо, пока пользователь не стер одно из подставленных данной процедурой значений.
В такой ситуации ошибки повторятся.
Ладно бы стер... он может нажать кнопку "Добавить" пару раз, и в справочнике легко появятся два, а то и три апреля...
Помните, я говорил в уроке 38, что обработчик ошибок нужен при выполнении Post? Давайте поправим ситуацию, пока не поздно.
Займемся этим оператором. А точнее - событием, предшествующим сохранению введенных в Grid значений в источнике, под сеткой подложенной таблице. Событие это носит название BeforePost. Именно в этот момент, перед выполнением операции сохранения данных, уместно сделать проверку на предмет: "Подходят ли нам введенные значения?"
Для этого напишем вот такой обработчик события BeforePost
procedure TMainFrm.ADOTableMOsBeforePost(DataSet: TDataSet);
function TheTestMos(): Boolean;
var
MyStr: String;
p: boolean;
begin
p:= True; // Признак успешности проверки
MyStr:= ADOTableMos.FieldByName('Name').AsString;
if (MyStr='')
then
begin
p:=False;
MyMessenger.TitleString:='Ошибка';
MyMessenger.MessageString:='Пустые значения в названии не допустимы';
MyMessenger.Buttons:=[mbOK];
MyMessenger.ShowMessage;
abort; // Не показывать пользователю стандартное сообщение об ошибке
end;
Result:=p;
end;
begin
If not TheTestMos
then
ADOTableMOs.Cancel;
end;
Попутно замечу, что выделив алгоритм проверки в отдельную функцию TheTestMos, я не преследовал никакой иной цели, кроме иллюстрации такой возможности. Такой прием был бы оправдан, если бы вызов функции повторялся в теле процедуры более одного раза.
Но это - так... лирика. Смоделировав некорректный ввод пользователя, мы получим на экран сообщение:
Первая часть проверки (попытка ввести мемориальный ордер без названия) успешно сработала.
Аналогично нужно сделать проверку введенного значения в поле Mes.
А еще необходимо как-то решить вопрос с двумя апрелями, что на мой взгляд интереснее.
Для этого понадобится запрос TADOQuery, который необходимо разместить на форме. Я назову его TempQuery.
И дополню функцию проверки:
// 1-я проверка на отсутствие названия мемориального ордера
MyStr:= ADOTableMos.FieldByName('Name').AsString;
if (MyStr='')
then
begin
p:=False;
MyMessenger.TitleString:='Ошибка';
MyMessenger.MessageString:='Пустые значения в названии не допустимы';
MyMessenger.Buttons:=[mbOK];
MyMessenger.ShowMessage;
abort; // Не показывать пользователю стандартное сообщение об ошибке
end;
// 2-я проверка на отсутствие номера месяца
MyStr:= ADOTableMos.FieldByName('Mes').AsString;
if (MyStr='')
then
begin
p:=False;
MyMessenger.TitleString:='Ошибка';
MyMessenger.MessageString:='Пустые значения в поле Месяц не допустимы';
MyMessenger.Buttons:=[mbOK];
MyMessenger.ShowMessage;
abort; // Не показывать пользователю стандартное сообщение об ошибке
end;
// 3-я проверка на ввод повторной записи
TempQuery.Active:=False;
TempQuery.SQL.Clear;
MyStr:='SELECT * FROM MOs WHERE (Name='''+MyStr+''') AND (Mes='+ADOTableMos.FieldByName('Mes').AsString+')';
TempQuery.SQL.Add(MyStr);
TempQuery.Active:=True;
If not TempQuery.Eof
Then
begin
p:=False;
MyMessenger.TitleString:='Ошибка';
MyMessenger.MessageString:='Запись с такими значениями уже имеется в базе данных...';
MyMessenger.Buttons:=[mbOK];
MyMessenger.ShowMessage;
Abort;
end;
TempQuery.Active:=False;
Запустив программу, после нажатия кнопки "Добавить" мемориальный ордер, ничего не меняя нажму "Сохранить" и опять увижу два апреля. Почему?
Вот тут я готов начать разговор о средствах отладки.
Простейшее из имеющегося богатого набора - это точка останова. Щелкните мышкой на сером поле в строке №967 ( TempQuery.SQL.Add(MyStr);). Появившаяся красная точка - точка, где программа остановится в процессе выполнения.
Если теперь навести курсор на переменную MyStr, то в хинте будет выведено значение, которое эта переменная имеет на данный момент:
В название месяца из той же переменной MyStr подставляется номер (4), полученный ею на этапе предыдущей проверки. Выход прост: переставьте местами 1-ю и 2-ю проверку:
Вот теперь, если оператор будет пытаться сделать некорректные действия, программа постарается его направить в мирное русло:
PS Точку останова нужно всегда ставить на следующей строчке, чтобы оператор присвоения значения (:=) уже был выполнен.
PPS Можно ли было вместо запроса использовать Locate?
Комментариев нет:
Отправить комментарий
Примечание. Отправлять комментарии могут только участники этого блога.