Delphi 3 и создание приложений баз данных

         

Создание отдельной формы


Пусть имеется ТБД "Сотрудники кафедры" и необходимо добавлять новые или корректировать существующие записи ТБД не в TDBGrid, а в отдельной форме. Назовем форму, в которой расположен TDBGrid, родительской. Назовем форму, в которой осуществляется добавление или корректировка записи, дочерней. Соответственно, TTable, расположеннье в этих формах, назовем родительским и дочерним. В этом случае порядок действий таков:

1. Заводим новую форму (дочернюю), в ней - TTable, TDataSource и группу компонентов TDBEdit (TDBComboBox, TDBLookup и т.д.), связанных между собой стандартным образом. Естественно, что компоненты TTable в родительской и дочерней формах должны указывать на одну таблицу базы данных. Желательно, чтобы и индексные файлы в них были одинаковы (свойство Table IndexName) Внешний вид этих форм показан соответственно на рис 8.35.а и 8.35 б.

И в родительской и в дочерней форме компонент TTable, связанный с ТБД "Сотрудники кафедры", имеет имя Table1. Поэтому в тех случаях, когда из дочерней формы нужно обратиться к Table1 в родительской форме, следует приписывать ей в качестве префикса название родительской формы, Prnt. Table7. В то же время, при обращении к Table1, принадлежащему дочерней форме, из самой дочерней формы можно указывать префикс {Chld.Table7), а можно и не указывать (Table1), например: Table1.GoToCurrent(PrntForm.Table1);

Здесь Table1.GoCurrent означает "выполнить метод GoToCnrrent, принадлежащий компоненту Table1 дочерней формы". Чтобы исключить разночтения, будем далее в программном коде явно указывать название формы при обращении к Table1

ChldForm.Table1.GoToCurrent(PrntForm.Table1);

2. В модуле unit, содержащем родительскую форму, разместим тестовую переменную SotrState, проинициализировав ее пустым значением:

const

SotrState : String = '';

Эта переменная пригодится нам в дальнейшем для передачи в дочернюю форму кода требуемой операции 'Insert' или 'Edit'. Можно, конечно, было переводить родительскую TTable в режимы dslnsert или dsEdit в родительской форме, однако применение такого подхода работает при совмещении указателей на компонент TDataSource (см. ниже раздел "Переназначение DataSource во время выполнения"), но не подходит при использовании в дочерней форме метода GoToCurrent: этот метод автоматически переводит родительский НД в режим dsBrowse

3. В родительской форме добавляем 2 кнопки для вызова дочерней формы одну (InsertButton) на добавление записи, другую (EditButton) - на корректировку При этом присваиваем переменной SotrState соответственно значение 'Insert' или 'Edit'.

После возврата из дочерней формы переменной SotrState присваивается пустое значение.

4 В процедуре дочерней формы, вызываемой при активизации формы, для случая добавлении записи переводим Table дочерней формы в состояние dsInsert, для случая корректировки - совмещаем курсоры Table родительской и дочерней форм.

ДочерняяТаЬ1е.GoToCurrent(PoдитeльcкaяTable) и затем переводим дочернюю форму в состояние dsEdit.

5 В дочерней форме добавляем клавиши "Запомнить" (PostButton) и "Отменить" (CancelButton) Кнопке "Отменить" приписываем модальный результат mrCancel (установив свойство ModalResult = mrCancel). Это важно, поскольку дочерняя форма будет вызываться из родительской как модальная Кнопке "Запомнить" свойство mrOk не назначаем (т е. ее свойство ModalResult = mrNone). В случае, если выполнение метода Post прошло успешно (и исключение не было возбуждено), явно устанавливаем результат работы родительской формы в mrOk: Chid.ModalResult := mrOk;

Это нужно для того, чтобы в случае неуспешности выполнения метода Post мы могли вернуть фокус управления на поля дочерней формы для того, чтобы пользователь попробовал скорректировать значения и повторить попытку выполнения метода Post для запоминания изменений, внесенных в запись НД в дочерней форме. Если бы кнопка "Отменить" автоматически выставляла модальный результат mrOk при своем нажатии, после завершения обработчика нажатия этой кнопки происходил бы выход из дочерней формы, несмотря на то, что содержащийся в обработчике текст в случае неудачи Post предписывает не выходить из дочерней формы, а передать фокус управления ее полям.

6. Как сказано выше, в обработчике нажатия клавиши "Запомнить" выполняем метод Post, а в обработчике нажатия клавиши "Отменить" - метод Cancel, по отношению к НД Table1 дочерней формы. Поскольку Table1 как дочерней, так и родительской формы, во-первых, связаны с одной и той же ТБД "Сотрудники кафедры", а во-вторых, курсоры этих НД совмещены (что актуально для режима dsEdit), выполнение Chid.Table1.Post равносильно выполнению Prnt.Table1 .Post. В случае возбуждения исключения EDBEngineError для простоты полагаем, что произошло дублирование ключевого поля (если в ТБД есть уникальные ключевые поля), хотя, впрочем, могут быть и другие причины.



Заметим, что для PrntForm.Table1 нужно вызывать метод Refresh, который обновляет содержимое НД в родительской форме.

Родительская форма:

// нажата кнопка "Вставить"

procedure TPrntForm.InsertButtonClick(Sender: TObject);

begin

SotrState := 'Insert';

ChldForm.ShowModal;

SotrState := '';

end;

// нажата кнопка "Изменить"

procedure TPrntForm.EditButtonClick (Sender: TObject) ;

begin

SotrState := 'Edit';

ChldForm.ShowModal;

SotrState := '';

end;

// нажата кнопка "Удалить"

procedure TPrntForm.DeleteButtonClick(Sender: TObject);

begin

IF MessageDIg('Подтвердите удаление записи',

mtlnformation, [mbYes, mbNo], 0) = mrYes THEN

Prnt.Table1.Delete;

end;

Дочерняя форма: при активизации дочерней формы переводим НД в режимы Insert или Edit. В последнем случае совмещаем курсоры

procedure TChldForm.FormActivate(Sender: TObject);

begin

IF SotrState = 'Edit' THEN

begin

ChldForm.Table1.GoToCurrent(PrntForm.Table1);

ChldForm.Table1.Edit;

end

ELSE

ChldForm.Table1.Insert;

end;

// обработчик нажатия клавиши "Запомнить"

procedure TChldForm.PostButtonClick(Sender: TObject);

begin

TRY

ChldForm.Table1.Post;

PrntForm.Table1.Refresh;

IF SotrState = 'Insert' THEN

PrntForm.Table1.GoToCurrent(ChldForm.Table1);

// при успешном выполнении Post выходим из модальной формы:

ChldForm.ModalResult := mrOk;

EXCEPT

on EDBEngineError do begin

ShowMessage('Дублирование ключевого поля!');

DBEditI.SetFocus; // возвращаемся на 1 поле DBEdit

end; {on}

ELSE

begin

ShowMessage('Ошибка иного типа при Post');

DBEditI.SetFocus;

end;

END; {try}

end;

// нажата кнопка "Отменить" (ModalResult = mrCancel)

Procedure TChldForm.CancelButtonClick (Sender: TObject);

begin ChldForm.Table1.Cancel;

end;

// если при выходе из дочерней формы набор данных - не в состоянии dsBrowse (что может быть при нажатии кнопки 'х') вверху слева, НД принудителъно переводится в режим dsBrowse

procedure TChldForm.FormDeactivate(Sender: TObject);

begin

IF ChldForm.Table1.State <> dsBrowse THEN

ChldForm.Table1.Cancel;

end;

КОММЕНТАРИЙ.

Может оказаться, что на момент выхода из формы методы Posг или Cancel к НД не выполнены (например, когда выход осуществляется также по нажатию иных кнопок, например "Выход"). Поэтому в родительской форме, после выхода из дочерней формы, будет нелишним проверить, находится ли НД в состоянии dsBrowse и если нет, принудительно перевести его в это состояния методом Cancel, отменяющим все сделанные изменения в записи. Естественно, что можно предусмотреть и иную реакцию на попытку выхода при НД, находящемся в режимах dslnsert или dsEdit.

Представление обеих форм в момент внесения изменений в ТБД из дочерней формы показано на рис.8.36.



Содержание раздела