Урок 1.10. Программирование баз данных в Delphi - создаем формы прихода продуктов на склад.
На этом уроке мы напишем процедуры для обработки событий для наших форм прихода, созданных на уроках 1.7. – 1.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;
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;
На этом
создание формы прихода закончено. Можно приступать к тестированию на наличие
ошибок.
Исходники к уроку можно скачатьздесь.
Здравствуйте! пожалуйста подскажите в чем ошибка Project storage.exe raised exception class EOleException with message 'Не удается найти строку для обновления. Некоторые значения могли быть изменены со времени ее последнего чтения'
Здравствуйте. В prihod.pas ругается компилятор на эту строчку: form_prihod_prod.DateTimePicker1.Date:=sysutils.Date; Пишет: E2003 undeclared identifier sysutils. В чем причина? Хотя в uses он объявлен.
Здравствуйте, подскажите такой вопрос, при попытке заполнения формы Приход: новое выдает ошибку "Индекс или ключ не может содержать пустое значение null", как ее исправить?
Судя по всему, при создании новой записи в базе у вас не заполняется ключевое поле одной из таблиц. Ключевое поле в таблице должно быть типа счетчик, тогда оно будет автоматом заполняться или вы должны сами программно предусмотреть заполнение таких полей.)))
Эта ошибка доступа к памяти, может возникать из-за чего угодно. В вашем случае скорее всего из-за ошибок в названиях полей базы данных. Что бы сказать более конкретно необходимо найти строку, которая вызывает данную ошибку, это можно сделать запуская программу в режиме отладки по клавише F7 и далее нажимая ее пока не найдете ошибку.)))
В процедуре procedure TForm_prihod_prod.FormCloseQuery(Sender: TObject; var CanClose: Boolean); это строка дает ошибку end //если записей нет, отменяем изменения else dm.table_prihod.cancel;( [EROR]prihod_pas';' exepted 'else' found) не могу понять в чем проблема то
Подскажите в чем ошибка, [Error]prihod_prod.pas(153): Undeclared identifier: 'dbedit_summa' выскакивает в этой строчке dm.table_prihod.FieldByName('sum').Value:=dbedit_summa.Field.Value;
Действительно в таком варианте программа не хочет работать, скорее всего проблема связана с тем что MDI форма вызывается из другой формы, а должна загружаться первой. Особо идей по этому поводу у меня нет. Могу предложить вариант вызова вашего приложения из другого приложения. Т.е. вы создаете простенькое приложение по проверке и регистрации пользователей, можете даже подключиться к базе, предварительно создав в ней таблицу с пользователями или делайте так как вы делали выше. После успешной проверки вы выполняете команду для запуска основного приложения: //открываем приложение Склад ShellExecute(handle, 'open', PWideChar('storage.exe'), nil, nil, SW_SHOWNORMAL); //убиваем приложение "Проверки пользователей" Application.Terminate;
Да, в uses необходимо добавить модуль shellapi.
Но тогда надо предусмотреть, что бы нельзя было открыть программу storage.exe минуя проверку пользователей. Для этого будем передавать какой нибудь ключевой параметр (например qwert) для запуска программы storage.exe,
а в storage.exe будем этот ключ проверять, если совпадает то открываем иначе убиваем его.
Проверять можно в событии OnCreate формы Form_general или в самом файле проекта (вызывается через меню Project -> View Source) сразу после begin добавляете строчку: if Paramstr(1)<> 'qwert' then halt ;
procedure TForm1.BitBtn2Click(Sender: TObject); begin close; end;
procedure TForm1.BitBtn1Click(Sender: TObject);
begin if edit1.Text='admin' then l:=1 else l:=0; if edit2.Text='4682' then p:=1 else p:=0; if (p+l)>1 then form_general.Show else ShowMessage('Неверный логин и (или) пароль!'); end;
Хотела чтобы при открытий запрашивал пароль, поэтому добавила новую форму в проект (изменила главную форму на это). Теперь не открываются меню. project project1.exe raised exception class econverterror with message 'Cannot create form No MDI form currently active'. process stopped/ use step or run to continue. в чем ошибка помогите пожалуйста!