ЛАБОРАТОРНАЯ РАБОТА № 10

Тема: Создаие формы прихода продуктов на склад.

Цель: Научиться создавать форму используя обработку событий

Оборудование и/или программное обеспечение: ПК, Delphi

Теоретическая часть

Операционная система Windows - многозадачная, т.е. несколько программ в ней могут функционировать одновременно. Когда, например, мы щёлкаем по кнопке в окне нашей программы, система Windowsопределяет, что произошло событие именно в нашей программе, и посылает ей сообщение об этом. Наша программа должна соответствующим образом отреагировать на него. Для этого мы, как программисты, должны написать код-обработчик этого события. Таким образом, структура программы для Windowsпредставляет собой набор подпрограмм, каждая из которых ответственна за обработку конкретного события и вызывается только при его возникновении. Удобство Delphi состоит в том, что мы избавлены от необходимости получать сообщения от Windows сами, Delphi это делает за нас. Каждый компонент имеет впечатляющий набор событий, на которые он может реагировать. Программист сам определяет, какие события в программе требуется обрабатывать.

ЛАБОРАТОРНАЯ РАБОТА № 10 - student2.ru

Откройте наш проект из предыдущего урока. Щелкните на компоненте Edit1. Он "появится" в Инспекторе объектов. Посмотрите: в Инспекторе объектов две вкладки: Properties (свойства) и Events (события). Перейдите на вкладку Events. Чтобы создать обработчик нужного события, нужно дважды кликнуть по нему мышкой. А если раскрыть выпадающий список, в нём будут находиться уже готовые обработчики, которые могут подходить для этого компонента. Таким образом, один обработчик может вызываться для обработки событий нескольких компонентов.

Изменим нашу программу так, чтобы текст на форме появлялся прямо в момент его ввода. В момент ввода у Edit1 меняется свойство Text - в нём появляется новая буква! Значит, воспользуемся событием onChange (change - изменение (англ.)), которое и происходит в этот момент. Итак:

1. Кликаем дважды по onChange, и оказываемся внутри только что созданного обработчика. 2. Присваиваем свойству Caption компонента Label1 значение свойства Text компонента Edit1, то есть делаем то же, что и в прошлом уроке: Label1.Caption := Edit1.Text; Или просто копируем из обработчика нажатия кнопки. 3. Запускаем программу, всё работает. Как видим, всё очень просто.


Теперь рассмотрим событие onClick. Как вы догадываетесь, это событие возникает при щелчке мышкой на компоненте. Воспользуемся им, чтобы очищать строку ввода от уже введённых символов. Вы сами уже должны сообразить, что сделать. В обработчике нужно присвоить свойству Text значение пустой строки. Строка в Delphi образуется заключением текста в одинарные кавычки (находятся на кнопке Э):
'Так в Delphi образуется строка'
Значит, пустая строка - это кавычки без текста: ''. Не должно быть даже пробела, иначе он окажется в строке ввода:

Edit1.Text:='';

Есть другой способ, воспользоваться специально предназначенным для этого методом компонента Edit, который так и называется Clear (очистка англ.):

Edit1.Clear;

Но подумайте о пользователе, который будет работать с вашей программой. Ему должно быть удобно. Если при вводе текста он захочет что-то исправить, и щёлкнет мышкой в том месте текста, где нужно внести изменение?! И всё сотрётся! Поэтому лучше использовать событие onEnter, которое происходит, когда вы "входите" в него и компонент получает фокус ввода, или использовать для очистки специальную кнопку и её событие onClick.
Конечно, у каждого компонента свой набор событий. Мы познакомились с тремя из них:

· onChange · onClick · onEnter

Другие важные события, которые есть почти у каждого визуального компонента:

· onExit - возникает, когда компонент теряет фокус ввода; · onDblClick - возникает при двойном щелчке мышкой по компоненту; · onKeyDown - когда при нажатии на кнопку на клавиатуре она оказалась в нижнем положении; · onKeyUp - когда при отпускании клавиатурной кнопки она оказалась в верхнем положении; · onKeyPress - возникает при нажатии на клавиатурную кнопку. От событий onKeyDown иonKeyUp оно отличается типом используемого параметра Key ; · onMouseDown - когда при нажатии кнопки мышки она оказалась в нижнем положении; · onMouseUp - когда при отпускании кнопки мышки она оказалась в верхнем положении; · onMouseMove - возникает при перемещении указателя мышки над компонентом. В начале работы любой программы происходит очень важное событие событие нашего основного компонента - Формы, onCreate. Оно происходит перед появлением Формы на экране. Это событие используется для задания свойств тех элементов программы, которые нуждаются в настройке, например, размеры и положение Формы на экране. Если вы захотите сделать невидимую программу, можно приравнять нулю ширину Width и высоту Height Формы. На этапе проектирования сделать этого нельзя, т.к. это помешает работе, поэтому делаем это по событию onCreate: Form1.Width := 0; Form1.Height := 0; Дополнительно нужно убрать и заголовок Формы, выбрав в Инспекторе Объектов параметр BorderStyle равным None. Теперь Форма на экране не появится. Единственным визуальным признаком останется появление её "значка" на панели задач. В дальнейшем я расскажу, как избавиться и от него.

Практическая часть

На этом уроке мы напишем процедуры для обработки событий для наших форм прихода, созданных на лабораторных работах 7-9.

Открываем форму прихода модуль (prihod) и пишем для события OnClick кнопки Button1 (Новая запись):

procedure TForm_prihod.Button1Click(Sender: TObject); begin //новая запись form_prihod_prod.Caption:='Приход: новое' ; dm.table_prihod.Edit; dm.table_prihod.append; form_prihod_prod.DateTimePicker1.Date:=sysutils.Date; form_prihod_prod.docum_number.Text:=''; form_prihod_prod.Showmodal; end;

для события OnClick кнопки Button2 (Удалить запись):

procedure TForm_prihod.Button2Click(Sender: TObject); begin //удаление записи if dbgrid1.DataSource.DataSet.RecordCount<>0 then begin if (MessageBox(Handle, 'Удалить запись?', 'Внимание !!!', MB_YESNO) = IDYES) then begin dm.table_prihod.Edit; form_prihod_prod.table_storage.Edit; //из таблицы storage dm.ADOQuery_delete.SQL.Clear; dm.ADOQuery_delete.DataSource:=dm.prihod; dm.ADOQuery_delete.SQL.Add('DELETE storage.*, storage.id FROM storage WHERE (((storage.id_prihod)=:id));'); dm.ADOQuery_delete.ExecSQL; dm.ADOQuery_delete.Active:=false; //из таблицы prihod dm.table_prihod.Edit; dm.table_prihod.Delete; end; end else ShowMessage('Нет записей для удаления'); end;

для события OnClick кнопки Button3 (Закрыть):

procedure TForm_prihod.Button3Click(Sender: TObject); begin //закрытие формы Close; end;

для события OnDblClick компонента DBGrid1:

procedure TForm_prihod.DBGrid1DblClick(Sender: TObject); begin //Двойной клик на записи, если записей еще нет, то создаем новую if dbgrid1.DataSource.DataSet.RecordCount=0 then begin form_prihod_prod.Caption:='Приход: новое' ; dm.table_prihod.Edit; dm.table_prihod.append; form_prihod_prod.docum_number.Text:=''; form_prihod_prod.DateTimePicker1.Date:=sysutils.Date; end //иначе заполняем форму prihod_prod текущими данными else begin dm.table_prihod.Edit; form_prihod_prod.table_storage.Edit; form_prihod_prod.table_storage.First; form_prihod_prod.docum_number.Text:= dm.table_prihod.FieldByName('number_docum').value; form_prihod_prod.DateTimePicker1.Date:= dm.table_prihod.FieldByName('date_prihoda').Value; end; //показываем форму prihod_prod form_prihod_prod.Caption:='Приход: '+dm.table_prihod.FieldByName('number_docum').AsString; form_prihod_prod.Showmodal; end;

для события OnActivate формы прихода form_prihod:

procedure TForm_prihod.FormActivate(Sender: TObject); begin //так как таблица приход использует данные из таблиц единицы измерения, категории продуктов, поставщики //и продукты //то мы должны проверить заполнены они или нет if form_general.table_ed_izmer.RecordCount=0 then begin ShowMessage('У Вас не заполнен справочник "Единиц измерения". Для продолжения работы Вам необходимо заполнить справочник.');close;end else begin if form_general.table_product_group.RecordCount=0 then begin ShowMessage('У Вас не заполнен справочник "Категории продуктов". Для продолжения работы Вам необходимо заполнить справочник.');close;end else begin if form_general.table_postav_ik.RecordCount=0 then begin ShowMessage('У Вас не заполнен справочник "Поставщики". Для продолжения работы Вам необходимо заполнить справочник.');close;end else begin if form_general.table_products.RecordCount=0 then begin ShowMessage('У Вас не заполнен справочник "Продукты". Для продолжения работы Вам необходимо заполнить справочник.');close;end else begin //обновляем данные form_general.table_ed_izmer.Refresh; form_general.table_product_group.Refresh; form_general.table_postav_ik.Refresh; form_general.table_products.Refresh; //установка фокуса при активации формы dbgrid1.SetFocus; end; end; end; end; end;

для события OnClose формы прихода form_prihod:

procedure TForm_prihod.FormClose(Sender: TObject; var Action: TCloseAction); begin //процедура закрытия формы Action:=cafree; end;

Открываем форму прихода продуктов модуль (prihod_prod) и пишем для события OnClick кнопки Button1 (Новая запись):

procedure TForm_prihod_prod.Button1Click(Sender: TObject); begin //новая запись if docum_number.Text='' then begin ShowMessage('Не заполнено поле "Номер документа"'); docum_number.SetFocus; end else begin if (table_copy_prihod.Lookup('number_docum', docum_number.text, 'number_docum')<>null) and (dm.table_prihod.FieldByName('number_docum').AsString<>docum_number.Text) then begin ShowMessage('Такой номер уже существует');docum_number.Text:=''; docum_number.SetFocus; end else begin if dblookup_postav_ik.Text='' then begin ShowMessage('Не заполнено поле "Поставщик"'); dblookup_postav_ik.SetFocus;end else begin if DateTimePicker1.ToString='' then begin ShowMessage('Не заполнено поле "Дата прихода"'); DateTimePicker1.SetFocus;end else begin dm.table_prihod.FieldByName('date_prihoda').Value:=DateTimePicker1.Date; dm.table_prihod.FieldByName('number_docum').Value:=docum_number.text; dm.table_prihod.Post; dm.table_prihod.edit; table_storage.Edit; table_storage.append; table_storage.FieldByName('id_prihod').Value:= dm.table_prihod.FieldByName('id').AsInteger; form_select_prod.Showmodal; end; end; end; end; end;

для события OnClick кнопки Button2 (Удалить запись):

procedure TForm_prihod_prod.Button2Click(Sender: TObject); begin //удалить запись if dbgrid1.DataSource.DataSet.RecordCount<>0 then begin if (MessageBox(Handle, 'Удалить запись?', 'Внимание !!!', MB_YESNO) = IDYES) then begin table_storage.Edit; table_storage.Delete; adoquery_summa.Active:=false; adoquery_summa.Active:=true; end; end else ShowMessage('Нет записей для удаления'); end;


для события OnClick кнопки Button3 (Закрыть):

procedure TForm_prihod_prod.Button3Click(Sender: TObject); begin //закрытие формы Close; end;

для события OnDblClick компонента DBGrid1:

procedure TForm_prihod_prod.DBGrid1DblClick(Sender: TObject); begin //двойной клик для редактирования записи if docum_number.Text='' then begin ShowMessage('Не заполнено поле "Номер документа"'); docum_number.SetFocus; end else begin if (table_copy_prihod.Lookup('number_docum', docum_number.text, 'number_docum')<>null) and (dm.table_prihod.FieldByName('number_docum').AsString<>docum_number.Text) then begin ShowMessage('Такой номер уже существует'); docum_number.Text:=''; docum_number.SetFocus; end else begin if dblookup_postav_ik.Text='' then begin ShowMessage('Не заполнено поле "Поставщик"'); dblookup_postav_ik.SetFocus;end else begin if DateTimePicker1.ToString='' then begin ShowMessage('Не заполнено поле "Дата прихода"'); DateTimePicker1.SetFocus;end else begin dm.table_prihod.FieldByName('date_prihoda').Value:= DateTimePicker1.Date; dm.table_prihod.FieldByName('number_docum').Value:= docum_number.text; dm.table_prihod.Post; dm.table_prihod.edit; table_storage.Edit; table_storage.FieldByName('id_prihod').Value:= dm.table_prihod.FieldByName('id').AsInteger; if table_storage.FieldByName('id_product_group').AsInteger<>0 then form_select_prod.DBLookup_product_group.KeyValue:= table_storage.FieldByName('id_product_group').Value; //открываем форму редактирования form_select_prod.Showmodal; end; end; end; end; end;

для события OnActivate формы прихода продуктов form_prihod_prod:

procedure TForm_prihod_prod.FormActivate(Sender: TObject); begin //пересчет итоговой суммы при активации формы adoquery_summa.Active:=false; adoquery_summa.Active:=true; end;

для события OnCloseQuery формы прихода продуктов form_prihod_prod:

procedure TForm_prihod_prod.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin //проверка перед закрытием формы и закрытие формы //сохранение формы if ( MessageBox(Handle, 'Cохранить документ?', 'Внимание !!!', MB_OkCANCEL)= IDOk) then begin if docum_number.Text='' then begin ShowMessage('Не заполнено поле "Номер документа"'); CanClose:=false;docum_number.SetFocus; end else begin if (table_copy_prihod.Lookup('number_docum',docum_number.Text,'number_docum')<>null) and (dm.table_prihod.FieldByName('number_docum').AsString<>docum_number.Text)then begin ShowMessage('Такой номер уже существует');CanClose:=false;docum_number.Text:=''; docum_number.SetFocus; end else begin if dblookup_postav_ik.Text='' then begin ShowMessage('Не заполнено поле "Поставщик"');CanClose:=false;dblookup_postav_ik.SetFocus;end else begin if DateTimePicker1.ToString='' then begin ShowMessage('Не заполнено поле "Дата прихода"');CanClose:=false;DateTimePicker1.SetFocus;end else begin dm.table_prihod.Edit; dm.table_prihod.FieldByName('date_prihoda').Value:=DateTimePicker1.Date; dm.table_prihod.FieldByName('number_docum').Value:=docum_number.text; dm.table_prihod.FieldByName('sum').Value:=dbedit_summa.Field.Value; dm.table_prihod.post; end; end; end; end; end //при отказе от сохранения, проверяем, если уже заполненные записи продуктов и если такие есть, то не даем закрыть форму, пока все не будет заполнено правильно else if dbgrid1.DataSource.DataSet.RecordCount<>0 then begin if docum_number.Text='' then begin ShowMessage('Не заполнено поле "Номер документа"'); CanClose:=false;docum_number.SetFocus; end else begin if (table_copy_prihod.Lookup('number_docum',docum_number.Text, 'number_docum')<>null) and (dm.table_prihod.FieldByName('number_docum').AsString <> docum_number.Text) then begin ShowMessage('Такой номер уже существует');CanClose:=false;docum_number.Text:=''; docum_number.SetFocus; end else begin if dblookup_postav_ik.Text='' then begin ShowMessage('Не заполнено поле "Поставщик"');CanClose:=false;dblookup_postav_ik.SetFocus;end else begin if DateTimePicker1.ToString='' then begin ShowMessage('Не заполнено поле "Дата прихода"');CanClose:=false;DateTimePicker1.SetFocus;end else begin dm.table_prihod.Edit; dm.table_prihod.FieldByName('date_prihoda').Value:= DateTimePicker1.Date; dm.table_prihod.FieldByName('number_docum').Value:= docum_number.text; dm.table_prihod.FieldByName('sum').Value:= dbedit_summa.Field.Value; dm.table_prihod.post; end; end; end; end; end //если записей нет, отменяем изменения else dm.table_prihod.cancel; end;

для события OnCalcFields компонента table_storage:

procedure TForm_prihod_prod.table_storageCalcFields(DataSet: TDataSet); begin //вычисляемое поле сумма table_storage.FieldByName('summa').Value:= table_storage.FieldByName('price').Value* table_storage.FieldByName('quantity').Value; end;

Открываем форму выбора продуктов прихода модуль (select_prod) и пишем для события OnClick кнопки Button1 (OK):

procedure TForm_select_prod.Button1Click(Sender: TObject); begin //Нажатие на кнопку ОК. Проверяем и сохраняем. if dblookup_products.Text='' then begin ShowMessage('Не заполнено поле "Продукт"');dblookup_products.SetFocus;end else begin if dblookup_ed_izmer.Text='' then begin ShowMessage('Не заполнено поле "Ед.изм."');dblookup_ed_izmer.SetFocus;end else begin if quantity.Text='' then begin ShowMessage('Не заполнено поле "Количество"');quantity.SetFocus;end else begin if price.Text='' then begin ShowMessage('Не заполнено поле "Цена"'); price.SetFocus;end else begin if DateTimePicker1.ToString='' then begin ShowMessage('Не заполнено поле "Срок реализации"'); DateTimePicker1.SetFocus;end else begin if ( MessageBox(Handle, 'Cохранить документ?', 'Внимание !!!', MB_OkCANCEL)= IDOk) then begin form_prihod_prod.table_storage.Edit; form_prihod_prod.table_storage.FieldByName('id_product_group').Value:= form_general.table_products.FieldByName('id_product_group').Value; form_prihod_prod.table_storage.FieldByName('date_realization').Value:= DateTimePicker1.Date; form_prihod_prod.table_storage.Post; end else form_prihod_prod.table_storage.Cancel; close; end; end; end; end; end; end;

для события OnClick кнопки Button2 (Отмена):

procedure TForm_select_prod.Button2Click(Sender: TObject); begin //кнопка отмена form_prihod_prod.table_storage.Cancel; form_select_prod.Close; end;

для события OnClick компонента DBLookup_products:

procedure TForm_select_prod.DBLookup_productsClick(Sender: TObject); begin //заполняем поля по умолчанию при выборе продукта DBLookup_ed_izmer.KeyValue:=products.DataSet.FieldByName('id_ed_izmer').Value; form_prihod_prod.table_storage.FieldByName('id_ed_izmer').Value:= dblookup_ed_izmer.KeyValue; DateTimePicker1.Date:=sysutils.Date+ products.DataSet.FieldByName('time_hraneniya').Value; end;

для события OnClick компонента DBLookup_product_group:

procedure TForm_select_prod.DBLookup_product_groupClick(Sender: TObject); begin //включем фильтр при выборе группы продукта form_general.table_products.Filtered:=true; form_general.table_products.Filter:='id_product_group='+ inttostr(DBLookup_product_group.KeyValue); //отключаем фильтр, если в выбранной категории нет продуктов if products.DataSet.RecordCount=0 then begin ShowMessage('Список продуктов пустой, выберите другую категорию или заполните справочник "Продукты".'); form_general.table_products.Filtered:=false; end; end;

для события OnClose формы form_select_prod:

procedure TForm_select_prod.FormClose(Sender: TObject; var Action: TCloseAction); begin //пересчитываем итоговую сумму и закрываем форму. form_prihod_prod.table_storage.Cancel; form_general.table_products.Filtered:=false; form_prihod_prod.adoquery_summa.Active:=false; form_prihod_prod.adoquery_summa.Active:=true; end;

Открываем форму «Справочник продуктов модуль (products) и пишем для события OnClick кнопки Button2 (Удалить запись):

procedure TForm_products.Button2Click(Sender: TObject); //удаление записи begin //если записи отсутствуют то выводим сообщение, иначе проверяем используется //ли данный продукт на складе, если нет то удаляем запись if dbgrid1.DataSource.DataSet.RecordCount<>0 then begin if (MessageBox(Handle, 'Удаление записей может привести к нарушению работы всей базы данных. Удалить запись?', 'Внимание !!!', MB_YESNO)= IDYES) then if (form_prihod_prod.table_storage.Locate('id_product', form_general.table_products.FieldByName('id').Value, [loCaseInsensitive,loPartialKey])) then ShowMessage('Нельзя удалить данный продукт, так как он используется в складе.') else form_general.table_products.Delete end else ShowMessage('Нет записей для удаления'); end;

а в uses добавим prihod_prod;

ЛАБОРАТОРНАЯ РАБОТА № 10 - student2.ru

На этом создание формы прихода закончено. Можно приступать к тестированию на наличие ошибок.

Вопросы для контроля

    1. для чего служит событие OnClick?
    2. Для чего служит событие OnDblClick?
    3. Опишите, что происходит в данном коде:

if dbgrid1.DataSource.DataSet.RecordCount<>0 then
begin
if (MessageBox(Handle, 'Удалить запись?', 'Внимание !!!', MB_YESNO) = IDYES) then
begin
table_storage.Edit;
table_storage.Delete;
adoquery_summa.Active:=false;
adoquery_summa.Active:=true;
end;
end
else ShowMessage('Нет записей для удаления');

    1. Опишите, что происходит в данном коде:

DBLookup_ed_izmer.KeyValue:=products.DataSet.FieldByName('id_ed_izmer').Value;
form_prihod_prod.table_storage.FieldByName('id_ed_izmer').Value:= dblookup_ed_izmer.KeyValue;
DateTimePicker1.Date:=sysutils.Date+ products.DataSet.FieldByName('time_hraneniya').Value;
end;

    1. Опишите, что происходит в данном коде:

form_prihod_prod.table_storage.Cancel;
form_general.table_products.Filtered:=false;
form_prihod_prod.adoquery_summa.Active:=false;
form_prihod_prod.adoquery_summa.Active:=true;
end;

Литература

4. Фаронов В.В. Программирование на языке высокого уровня: Учебник для вузов. -СПб.: Питер, 2003.

5. Бобровский С.И. Delphi 7. Учебный курс. - СПб.: Питер, 2005.

6. Кетков Ю.Л., Кетков А.Ю. Практика программирования: Visual Basic, C++ Builder, Delphi. - СПб.: БХВ - Петербург, 2005.

Наши рекомендации