- •1. Методика построения прикладной системы
- •1.1. Определение назначения и задач приложения
- •1.2. Проектирование бд и прикладных процессов
- •1.3. Реализация проекта
- •1.4. Тестирование приложения
- •1.5. Установка (инсталляция) приложения
- •2. Использование методики
- •2.1. Проектирование прикладных процессов
- •2.2. Реализация прикладной системы
- •2.2.1. Создание главной формы fmMainform
- •2.2.2. Создание формы fmAboutsys
- •2.2.3. Создание формы fmEditflat
- •2.2.4. Создание формы fmShowflat
- •2.2.5. Создание формы fmEditpers
- •4. Порядок выполнения лабораторной работы
- •6. Рекомендуемая литература
2.2.5. Создание формы fmEditpers
Выберем команду File|New Form и нажмем в появившемся окне Browse Gallery кнопку OK, чтобы включить в проект пустую форму Blank form.
Поместим в эту форму 8 компонентов Label, 5 компонентов Button, 4 компонента DBEdit и по одному компоненту DBText, DBComboBox, DBLookupCombo, DBGrid, DBNavigator, расположив их так, как показано на рис.9. Поместим также на любое свободное место в форме 5 компонентов Table и 3 компонента DataSource.
Зададим для формы значение свойства Name=fmEDITPERS. Значения свойства Name для других компонентов установим в соответствии с указаниями, приведенными на рис.9, и рекомендациями, следующими за табл.3.
Значения свойства Caption для компонентов Label устанавливаются согласно надписям, поясняющим содержимое областей создаваемой формы и показанным на рис.9. Значение свойства Caption для компонентов Button задаются согласно надписям на кнопках (см. рис.9).
Свойства компонентов Table и DataSource устанавливаются в соответствии с табл.9-10.
Таблица 9
Значения свойств компонентов Table
Свойство |
Компоненты | ||||
|
Table1 |
Table2 |
Table3 |
Table4 |
Table5 |
Name |
taPERSON |
taHAVE_D |
taFLAT |
taTPHONE |
taPROFIT |
DatabaseName |
dbTUTOR |
dbTUTOR |
dbTUTOR |
dbTUTOR |
dbTUTOR |
TableName |
PERSON.DB |
HAVE_D.DB |
FLAT.DB |
TPHONE.DB |
PROFIT.DB |
Active |
True |
True |
True |
True |
True |
Таблица 10
Значения свойств компонентов DataSource
Свойство |
Компоненты | ||
|
DataSource1 |
DataSource2 |
DatSource3 |
Name |
dsPERSON |
dsHAVE_D |
dsFLAT |
DataSet |
taPERSON |
taPERSON |
taFLAT |
С помощью Редактора полей для каждого компонента Table следует сформировать набор полей, используя последовательность действий, описанную в разделе 2.2.4 и поясненную на рис.11-12. Для таблиц taFLAT, taTPHONE и taPROFIT набор полей совпадает с перечнем полей (атрибутов) для находящейся в базе данных на диске таблицы с именем TableName, которая связана с компонентом Table.
Для таблицы taPERSON в набор полей включаются все поля, имеющиеся в таблице (файле) PERSON.DB, и одно вычисляемое поле Ntel типа StringField для хранения номера телефона, установленного в квартире. Для вычисления значения этого поля необходимо предусмотреть процедуру обработки события OnCalcFields для таблицы taPERSON. Текст этой процедуры, имя которой taPERSONCalcFields формируется автоматически системой Delphi, приведен на листинге 8. Значение вычисляемого поля Ntel таблицы taPERSON в процедуре обозначается как taPERSONNtel.Value.
Листинг 8. Процедура определения номера телефона
procedure TfmEDITPERS.taPERSONCalcFields(DataSet: TDataset);
begin
with taTPHONE do {Найти номер телефона по адресу}
begin
Open;
IndexName := 'Adr'; {Задать вторичный индекс}
First;
SetKey;
FieldByName('Adr').AsString :=
taPERSON.FieldByName('Adr').AsString;
if GotoKey then {Запись найдена по ключу}
taPERSONNtel.Value := FieldByName('Ntel').AsString
else {Запись не найдена}
taPERSONNtel.Value := '';
end;
end;
Для таблицы taHAVE_D в набор полей включаются все поля, имеющиеся в таблице (файле) HAVE_D.DB, и два вычисляемых поля: Source типа StringField с названием источника дохода и Size типа CurrencyField с размером дохода. Для вычисления значений этих полей необходимо предусмотреть процедуру обработки события OnCalcFields для таблицы taHAVE_D. Текст этой процедуры taHAVE_DCalcFields приведен на листинге 9. Значения вычисляемых полей отыскиваются в таблице taPROFIT по идентификатору вида дохода Id.
Листинг 9. Процедура вычисления полей Source и Size таблицы taHAVE_D
procedure TfmEDITPERS.taHAVE_DCalcFields(DataSet: TDataset);
begin
with taPROFIT do
begin
DisableControls;
Open;
First;
SetKey;
FieldByName('Id').AsInteger :=
fmEDITPERS.taHAVE_D.FieldByName('Id').AsInteger;
GotoKey; {Поиск записи по ключу}
EnableControls;
end;
taHAVE_DSource.Value := taPROFITSource.Value;
taHAVE_DSize.Value := taPROFITMoneys.Value;
end;
Данные из таблицы taHAVE_D будут отображаться в компоненте grHAVE_D. Чтобы на экране были видны значения только полей Source, Size и Comment с соответствующими заголовками “Источник”, “Размер”, “Пояснение”, значения свойств полей в сформированном наборе должны быть установлены согласно табл.11.
Таблица 11
Значения свойств полей для компонента taHAVE_D
FieldName |
Calculated |
DisplayLabel |
Visible |
Nom |
False |
Nom |
False |
Id |
False |
Id |
False |
Source |
True |
Источник |
True |
Size |
True |
Размер |
True |
Comment |
True |
Пояснение |
True |
Значения свойств, общих для визуальных компонентов, управляющих данными, задаются в соответствии с табл.12. Для компонента dcPol дополнительно устанавливается значение свойства Items, содержащего допустимое обозначение пола, которое помещается в поле Pol таблицы taPERSON. Действия по установке значения свойства Items описаны в разделе 2.2.3. Для компонента deSumD дополнительно задается значение свойства ReadOnly=True, чтобы запретить запись общего дохода с помощью клавиатуры, поскольку целесообразно общий доход вычислять автоматически на основе данных, имеющихся в таблицах taHAVE_D и taPROFIT.
Таблица 12
Значения общих cвойств визуальных компонентов
Name |
DataSource |
DataField |
Name |
DataSource |
DataField |
teNom |
dsPERSON |
Nom |
deSumD |
dsPERSON |
SumD |
deFIO |
dsPERSON |
FIO |
deNtel |
dsPERSON |
Ntel |
deRdate |
dsPERSON |
Rdate |
grHAVE_D |
dsHAVE_D |
-- |
dcPol |
dsPERSON |
Pol |
naHAVE_D |
dsHAVE_D |
-- |
lcAdr |
dsPERSON |
Adr |
|
|
|
Для компонента naHAVE_D дополнительно устанавливается значение свойства VisibleButtons=[nbFirst,nbPrior, nbNext, nbLast, nbDelete, nbEdit, nbPost, nbCancel], поскольку вместо кнопки навигатора nbInsert в форме предусмотрена кнопка “Новый доход”.
С помощью компонента lcAdr значение поля Adr таблицы taPERSON устанавливается путем выбора из списка возможных значений, хранящихся в таблице taFLAT; список появляется при щелчке на кнопке со стрелкой. Для настройки компонента lcAdr нужно задать значения свойств DataSource и DataField, указанное в табл.12, а также значения свойств LookupSource, LookupField, LookupDisplay, необходимые для связи с таблицей taFLAT: LookupSource=dsFLAT (DataSource, соответствующий таблице taFLAT); LookupField=Adr (ключевое поле таблицы taFLAT, значение которого должно соответствовать значению поля, указанного в свойстве DataField); LookupDisplay=Adr (поле таблицы taFLAT, значение которого отображается на экране в компоненте lcAdr).
Примечание.Компонент DBLookupCombo обеспечивает равенство значений полей DataField и LookupField в таблицах, связанных с DataSource и LookupSource соответственно, и позволяет отображать значение поля LookupDisplay на экране в компоненте DBLookupCombo.
В компоненте grHAVE_Dдолжны отображаться виды доходов жителя, номер которого выводится в области компонентаteNom. Для этого между таблицамиtaPERSON иtaHAVE_Dнеобходимо установить связь “главная/подчиненная”(master/detailed), задав следующие значения свойств подчиненной таблицыtaHAVE_D:MasterSource=dsPERSON; MasterFields=Nom. Строки (записи) в подчиненной таблице должны быть упорядочены с помощью существующего индекса по значениям полей, соответствующих полям, указанным в свойствеMasterFields.Для таблицыtaHAVE_Dдействует первичный индекс с составным ключом(Nom, Id), обеспечивающим автоматическую сортировку по значениям поляNom, поэтому специального указания об используемом индексе не требуется, хотя можно было бы установить свойствоIndexFieldNames=Nom для полной ясности.
Для вычисления общего дохода жителя и записи его в поле SumD таблицыtaPERSONпоместим в форму компонентQuery со страницыData Accessпалитры компонентов и зададим его свойстваName=quSumD, DatabaseName=dbTUTOR.Затем дважды щелкнем на свойствеSQL и в появившемся окнеString list editor наберем запрос на языкеSQL, с помощью которого будет вычисляться общий доход жителя, помещаемый в полеSummaкомпонентаquSumD (см. листинг 10).
Листинг 10.SQL-запрос для вычисления общего дохода
selectSUM(PROFIT.Moneys) Summa, HAVE_D.Nom
fromHAVE_D, PROFIT
whereHAVE_D.Id=PROFIT.IdandHAVE_D.Nom=:Nom
group byNom
Параметром SQL-запроса является величина:Nom, обозначающая номер жителя. Тип параметра(Integer) задается как значение свойстваParams компонентаquSumD. С помощью Редактора полей для компонентаquSumD следует сформировать набор полей, включив в него полеSumma.
SQL-запрос должен выполняться каждый раз после записи новой строки в таблицуtaHAVE_Dили после удаления строки из нее, т.е. при наступлении событияAfterPost илиAfterDelete.Текст процедуры обработки событияAfterPost приведен на листинге 11.
Листинг 11. Процедура вычисления общего дохода
procedure TfmEDITPERS.taHAVE_DAfterPost(DataSet: TDataset);
begin
with quSumD do
begin
if Active then Close; {Закрыть таблицу}
ParamByName('Nom').AsInteger:=taPERSONNom.AsInteger; {Задать значение параметра}
Open; {Выполнить SQL-запрос}
taPERSONSumD.Value:=quSumDSumma.Value; {Записать общий доход}
end;
end;
Эта же процедура должна выполняться при наступлении события AfterDelete.Чтобы использовать ее повторно, нужно для таблицыtaHAVE_Dв окне Инспектора объектов на странице событий выделить строку, соответствующую событиюAfterDelete, щелкнуть в этой строке на кнопке со стрелкой и выбрать из появившегося списка имя процедурыtaHAVE_DAfterPost.
Теперь перейдем к компонентам Button.Для кнопок “Отмена” и “Выход” процедуры обработки событияOnClick во многом сходны с ранее рассмотренными (см. листинг 3) и приведены на листинге 12.
Листинг 12. Процедуры обработки события OnClick для
кнопок Отмена и Выход
procedure TfmEDITPERS.buCancelClick(Sender: TObject);
begin
with taPERSON do
begin
Cancel; { Отменить изменения, }
Edit; { но }
taHAVE_DAfterPost(taHAVE_D); { вычислить и }
Post; { запомнить общий доход }
end;
fmEDITPERS.Close;
end;
procedure TfmEDITPERS.buExitClick(Sender: TObject);
begin
with taPERSON do
begin
if (State in [dsEdit,dsInsert]) and Modified then
Post; {Сохранить изменения, если действует режим }
end; {редактирования или дополнения и запись изменялась}
KeyValue := {Запомнить значение ключа для fmSHOWPERS }
taPERSON.FieldByName('Nom').AsInteger;
fmEDITPERS.Close;
end;
Процедура обработки события OnClickдля кнопки “Сведения о квартире” активизирует формуfmEDITFLAT для просмотра, изменения или регистрации сведений о квартире (см. листинг 13). Если регистрируется новая квартира, то сведения о ней должны быть отражены в таблицеtaFLAT,принадлежащей формеfmEDITPERS, иначе новый адрес не будет появляться в списке связанном с компонентомlcAdr.Для обновления таблицыtaFLAT после возврата из формыfmEDITFLATвызывается процедураRefresh_taFLAT,текст которой приведен на листинге 13. Заголовок процедурыRefresh_taFLAT помещается в разделеprivate классаTfmEDITPERS.
Листинг 13. Процедуры обработки события OnClick для кнопки
Сведения о квартире и обновления таблицы taFLAT
procedure TfmEDITPERS.buEditFlatClick(Sender: TObject);
begin
if taPERSONAdr.Value='' then {Адрес отсутствует }
begin
fmEDITFLAT.Editing :=False;
fmEDITFLAT.KeyValue:='';
end
else
begin
fmEDITFLAT.Editing := True;
fmEDITFLAT.KeyValue:= taPERSONAdr.Value;
end;
fmEDITFLAT.ShowModal;
Refresh_taFLAT; {Обновить таблицу }
if (fmEDITFLAT.KeyValue<>'')then
begin {Адрес задан }
lcAdr.DisplayValue := fmEDITFLAT.KeyValue; {Показать адрес }
taPERSONAdr.Value := fmEDITFLAT.KeyValue; {Записать адрес }
taPERSONCalcFields(taPERSON); {Вычислить номер телефона}
end;
end;
procedure TfmEDITPERS.Refresh_taFLAT;
begin
with taFLAT do
begin
First;
SetKey;
FieldByName('Adr').AsString := fmEDITFLAT.KeyValue;
GotoKey; {Поиск записи по ключу }
end;
end;
Процедура обработки события OnClick для кнопки “Сведения о телефоне” активизирует форму fmEDITPHON для просмотра, изменения или регистрации сведений о телефоне (см. листинг 14). Если регистрируется новый телефон, то сведения о нем будут отражены в таблице taTPHONE, принадлежащей форме fmEDITPERS, при поиске номера телефона по адресу процедурой taRERSONCalcFields.
Листинг 14. Процедура обработки события OnClick для
кнопки Сведения о телефоне
procedure TfmEDITPERS.buEditPhoneClick(Sender: TObject);
begin
if taPERSONNtel.Value='' then {Телефон отсутствует }
begin
fmEDITPHON.Editing := False;
fmEDITPHON.KeyValue:= ''; {Если не изменится,то была Отмена}
end
else
begin
fmEDITPHON.Editing := True;
fmEDITPHON.KeyValue:= taPERSONNtel.Value;
end;
fmEDITPHON.ShowModal;
taPERSONCalcFields(taPERSON); {Вычислить номер телефона }
end;
Процедура обработки события OnClick для кнопки “Новый доход” добавляет новую строку в таблицуtaHAVE_D и активизирует формуfmEDITPROF,используемую для выбора нужного вида дохода (см. листинг 15). После возврата из формыfmEDITPROFзаполняются поляNom иIdдобавленной строки в таблицеtaHAVE_Dи строка записывается в таблицу.
Листинг 15. Процедура обработки события OnClick
для кнопки Новый доход
procedure TfmEDITPERS.buNewProfitClick(Sender: TObject);
begin
taHAVE_D.Append;
fmEDITPROF.Editing := True;
fmEDITPROF.KeyValue:= 0;
fmEDITPROF.ShowModal;
if fmEDITPROF.KeyValue>0 then {Выбор сделан}
begin
with taPERSON do
if (State in [dsEdit,dsInsert]) and Modified then
begin
Post; {Сохранить изменения, если действует режим редак-}
{тирования или дополнения и запись изменялась, }
Edit; { чтобы установить значение поля Nom}
end;
taHAVE_DNom.Value := taPERSONNom.Value;
taHAVE_DId.Value := fmEDITPROF.KeyValue;
taHAVE_D.Post;
end
else {Выбор не сделан}
taHAVE_D.Cancel;
end;
В процедуре учтена особенность полей типа Autoincrement: при добавлении новой строки в таблицу методомAppend илиInsertзначение в поле этого типа заносится только после выполнения методаPost для таблицы.
Для автоматического определения номера телефона по заданному адресу предусмотрим для компонента lcAdrпроцедуру обработки событияOnChange,которое наступает при переходе фокуса из области компонентаlcAdr, если изменилось значение адреса. Текст процедуры показан на листинге 16.
Листинг 16. Процедура обработки события OnChange
для компонента lcAdr
procedure TfmEDITPERS.lcAdrChange(Sender: TObject);
begin
with taPERSON do
if (State in [dsEdit,dsInsert]) and Modified then
taPERSONCalcFields(taPERSON); {Определить номер телефона}
end;
Создаваемая форма может вызываться в режимах регистрации или изменения сведений о жителе. При активизации формы fmEDITPERSнеобходимо задать соответствующий заголовок формы и обеспечить доступ к нужной записи таблицы taPERSON.Эти действия выполнит процедура обработки событияOnActivate,текст которой приведен на листинге 17.
Листинг 17. Процедура обработки события OnActivate
procedure TfmEDITPERS.FormActivate(Sender: TObject);
begin
if Editing then
begin
Caption := 'Изменение сведений о жителе';
with taPERSON do
begin
DisableControls;
First;
SetKey;
FieldByName('Nom').AsInteger := KeyValue;
GotoKey; {Поиск записи по ключу}
EnableControls;
Edit; {Режим редактирования}
end;
end
else
begin
Caption := 'Регистрация сведений о жителе';
taPERSON.Append; {Режим дополнения }
end;
end;
В этой и других процедурах используется признак режима EditingтипаBooleanи признакKeyValueтипаLongint,содержащий значение первичного ключа таблицыtaPERSON.Эти переменные следует объявить в разделеpublicклассаTfmEDITPERS.
Создаваемая форма активизирует формы fmEDITFLAT, fmEDITPROF иfmEDITPHON.Чтобы они были доступны, в разделImplementationмодуля создаваемой формы следует поместить предложение
uses EDITFLAT, EDITPROF, EDITPHON;
Сохраним созданную форму и проект командой File|Save Project, указав в качестве имени модуля созданной формы имяEDITPERS.На этом создание формыfmEDITPERSзавершается. Остается связать ее с пунктом меню “Житель” в главной форме и с кнопкой на панели быстрого доступаsbNewPerson аналогично тому, как подобные связи устанавливались для формыfmEDITFLAT (см. окончание раздела 2.2.3).
Сохранив изменения командой File|Save Project, можно проверить работоспособность проекта, осуществив активизацию созданной формы из меню или кнопкой на панели быстрого доступа и убедившись в правильном функционировании формыfmEDITPERS.
Лабораторное задание
Ознакомиться с методикой построения прикладной системы для работы с базой данных, освоить методику на примере учебного задания и использовать ее для выполнения конкретного варианта задания.