среда, 25 апреля 2012 г.

Урок 40. Кодификаторы

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

Теперь книг много разных. Но и в хороших книгах, которые встречаются не часто, по прежнему не просто найти ответ на вопрос "когда же достаточно электронной таблицы типа Excel, а в каком случае удобно использовать базу данных?"

И вывел я для себя вот такую формулу много лет назад:

все, из чего можно составить список и пронумеровать - есть содержимое для отдельной таблицы базы данных.



Если вернуться на пару десятков уроков назад, то в структуре созданной нами для реализации функционала программы "Расходы" присутствует ряд таких таблиц:
  • Перечень валют
  • Перечень счетов
  • Перечень мемориальных ордеров
На них же ссылаются пункты меню:


В этом уроке я расскажу, как наполнить программу возможностью обрабатывать различные справочники (кодификаторы).

Сразу хотелось бы предупредить, что вряд ли я сообщу что-то новое в дополнение к тому, что уже было сказано в предыдущих уроках.


Итак, напомню общий алгоритм:

1. Добавить форму в проект
2. Прописать ссылку на модуль формы в Uses вызывающей формы
3. Исключить из автоматически запускаемых
4. Добавить процедуру (или несколько) для вызова новой формы

1. Форма для работы со списком счетов будет выглядеть так:


Последняя колонка должна быть недоступной для редактирования, так как значение для нее будет задаваться как значение по умолчанию, а для его изменения мы позже создадим инструмент (форму).


2. Укажите ссылку в разделе:

implementation
  Uses Main;

С учетом этого, источником данных для этой формы может вполне служить источник данных, расположенный на главной форме. Установите в свойствах: DataSource=MainFrm.DataSourceAcc.



3. Напомню: Меню-Project-Options:




4. В описание класса главной формы:

type
  TMainFrm = class(TForm)
...
в секцию нужно добавить описание новой подпрограммы:
  private
    { Private declarations }
    procedure ShowAccounts();

А затем в секции реализации (implementation) 

дополнить ссылки на другие модули еще одной

implementation
Uses
  MOs
, Oborot
, Accounts
;

ну, и написать, собственно, код этой процедуры:

procedure TMainFrm.ShowAccounts();
Begin
  Application.CreateForm(TAccountsFrm, AccountsFrm);
  AccountsFrm.ShowMoDal;
  AccountsFrm.Free;
  StatusBarUpdate;
end;

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

И последнее - создать Action или напрямую - обработчик выбора пункта меню "Кодификаторы - Счета"

procedure TMainFrm.N1Click(Sender: TObject);
begin
  MySelect.MySel_IDAcc:=0;
  MySelect.MySel_AccName:='';
  ShowAccounts;
end;

Теперь стоит задуматься: базу данных мы спроектировали надежную (это я про то, что после компиляции программы "Расходы" мне удалось добавить новую запись в список (кодификатор) счетов, и ничего не рухнуло): при добавлении новой записи подставились какие-то значения по-умолчанию.

Но, может быть, удобнее задать иные? Переделать базу данных можно, пока она у Вас одна, задачка локальная и Вы - сам себе командир. Но, если Вы работаете над большим и сложным проектом, то это не всегда бывает возможно. Бывает даже так: кто-то разрабатывает интерфейсы, а совсем другие люди разрабатывают или уже разработали базы данных.

Поэтому, я предлагаю написать еще одну процедуру, которая будет подставлять нужные нам значения по умолчанию в только что добавленную новую запись (для события AfterInsert компонента ADOTableAcc, расположенного на главной форме):

procedure TMainFrm.ADOTableAccAfterInsert(DataSet: TDataSet);
begin
  ADOTableAcc.FieldByName('Val').Value:=MySelect.MySel_IDVal;
  ADOTableAcc.FieldByName('Ost_D').Value:=0;
  ADOTableAcc.FieldByName('Ost_K').Value:=0;
  ADOTableAcc.FieldByName('Analiz').Value:=True;
  ADOTableAcc.FieldByName('Groups').Value:=False;
end;

Обращаю Ваше внимание, что последний оператор задает значение, отличное от значения по умолчанию, установленное в конструкторе таблицы базы данных:



Еще один момент:

для того же компонента  ADOTableAcc нужен обработчик события BeforeEdit (в момент начала редактирования необходимо запомнить ID строки, соответствующей редактируемому счету)

procedure TMainFrm.ADOTableAccBeforeEdit(DataSet: TDataSet);
begin
  p_ID:= ADOTableAcc.FieldByName('ID').value;
end;


И последнее:

без проверки введенных значений возможна ситуация задваивания значений:


Такое положение в учете не допустимо.
Поэтому, прежде, чем сохранить новое или отредактированное значение счета, нужно учинить ему очень строгую проверку по событию BeforePost:


procedure TMainFrm.ADOTableAccBeforePost(DataSet: TDataSet);
Var MyStr: String;
begin


  MyStr:= ADOTableAcc.FieldByName('Name').Text;
  if (MyStr='')
  then
  begin
    MyMessenger.TitleString:='Ошибка';
    MyMessenger.MessageString:='Пустые значения не допустимы';
    MyMessenger.Buttons:=[mbOK];
    MyMessenger.ShowMessage;
    abort;
    exit;
  end;


  TempQuery.Active:=False;
  TempQuery.Connection:=ADOConnection1;
  TempQuery.SQL.Clear;
  TempQuery.SQL.Add('SELECT * FROM Accounts WHERE (Name='''+MyStr+''') AND (ID<>'+IntToStr(p_ID)+')');
  TempQuery.Active:=True;
  If not TempQuery.Eof
  Then
    begin
      MyMessenger.TitleString:='Ошибка';
      MyMessenger.MessageString:='Счет '''+MyStr+''' уже есть.';
      MyMessenger.Buttons:=[mbOK];
      MyMessenger.ShowMessage;
      ADOTableAcc.FieldByName('Name').Text:='';
      Abort;
    end;
  TempQuery.Active:=False;


end;


В результате срабатывания этой процедуры возможны предупреждения о повторяющемся или пустом значении:



Аналогичные (но, спешу успокоить: чуть более простые) нужно проделать для других кодификаторов (Мемориальные ордера и Валюты).


procedure TMainFrm.N2Click(Sender: TObject);
begin


  // Обработка пункта меню  Кодификаторы-Мемориальные ордера
  ShowMOs;


end;

- кодификатор мемориальных ордеров у нас уже имеется, остается только выполнить обработку пункта меню.

Для кодификатора валют понадобится добавить на главную форму пару компонентов (таблицу и источник данных: TADOTable и TDataSource), назначить их свойства, как уже это делали не однократно, не забыть добавить активацию этой таблицы в соответствующей процедуре и написать вызов формы:




procedure TMainFrm.N_ValClick(Sender: TObject);
begin


  // Вызов справочника валют
  Application.CreateForm(TValFrm, ValFrm);
  ValFrm.ShowModal;
  ValFrm.Free;
  StatusBarUpdate;


  // Фильтр по счетам одной валюты
  ADOTableAcc.Filter:='Val='+IntToStr(MySelect.MySel_IDVal);
  ADOTableAcc.Filtered:=True;


end;



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


Комментариев нет:

Отправить комментарий