Построение приложений локальных баз данных средствами delphi
Цель работы: научиться разрабатывать клиентские приложения в среде Delphi для управления базами данных.
Порядок выполнения работы
1. Постановка задачи. В среде Delphi разработать проект клиентского приложения для управления базой данных «Поваренная книга» (см. задания к лабораторной работе № 15).
2. Создать следующие формы:
MainForm (модуль MainUnit),
RecipeForm (модуль RecipeUnit),
FoodForm (модуль FoodUnit),
ComponentForm (модуль ComponentUnit),
ListCalcForm (модуль ListCalcUnit).
3. Расположить и настроить компоненты на формах.
3.1. На форме MainForm:
FoodGrid: TDBGrid
Align = alBottom
DataSouce = FoodDataSource
Splitter1: TSplitter
Align = alBottom
RecipesGrid: TDBGrid
Align = alLeft
DataSouce = RecipesDataSource
Splitter2: TSplitter
Align = alLeft
ComponentsGrid: TDBGrid
Align = alClient
DataSouce = ComponentsDataSource
CookBookConnection: TADOConnection
LoginPrompt = False
FoodTable: TADOTable
Connection = CookBookConnection
TableName = Food
RFLinksTable: TADOTable
Connection = CookBookConnection
TableName = RF_Links
CategoryTable: TADOTable
Connection = CookBookConnection
TableName = Categories
RecipesTable: TADOTable
Connection = CookBookConnection
TableName = Recipes
ComponentsQuery: TADOQuery
Connection = CookBookConnection
RecipesQuery: TADOQuery
Connection = CookBookConnection
SQL =
select Recipes.ID, R_Name, Persons, C_Name, Category_ID
from Recipes, Categories
where Category_ID=Categories.ID
order by R_Name
OpenDBDialog: TOpenDialog
Filter = Файлы Access|*.mdb
FoodDataSource: TDataSource
DataSet = FoodTable
RecipesDataSource: TDataSource
DataSet = RecipesQuery
ComponentsDataSource: TDataSource
DataSet = ComponentsQuery
CookBookMenu: TMainMenu
Создание элементов меню:
Группа | Пункт (Name) | Подпись (Caption) |
Файл | OpenDBItem | Открыть БД |
CloseDBItem | Закрыть БД | |
ExitItem | Выход | |
Таблицы | NewRecipeItem | Новый рецепт |
EditRecipeItem | Изменить рецепт | |
AddFoodItem | Добавить продукт к рецепту | |
RemoveFoodItem | Убрать продукт из рецепта | |
EditQuantityItem | Изменить количество продукта | |
DeleteRecipeItem | Удалить рецепт | |
NewFoodItem | Новый продукт | |
EditFoodItem | Изменить продукт | |
DeleteFoodItem | Удалить продукт | |
Сервис | ListCalcItem | Расчет сметы |
3.2. На форме RecipeForm:
Label1: TLabel
Caption = Название:
Label2: TLabel
Caption = Персон:
Label3: TLabel
Caption = Категория:
NameEdit: TEdit
PersonsEdit: TEdit
CategoryCombo: TComboBox
OKButton: TButton
Caption = ОК
CancelButton: TButton
Caption = Отмена
3.3. На форме FoodForm:
Label1: TLabel
Caption = Название:
Label2: TLabel
Caption = Калорийность:
Label3: TLabel
Caption = Цена
NameEdit: TEdit
EnergyEdit: TEdit
PriceEdit: TEdit
OKButton: TButton
Caption = ОК
CancelButton: TButton
Caption = Отмена
3.4. На форме ComponentForm:
Label1: TLabel
Caption = Количество продукта:
QuantityEdit: TEdit
OKButton: TButton
Caption = ОК
CancelButton: TButton
Caption = Отмена
3.5. На форме ListCalcForm
Label1: TLabel
Caption = Количество персон:
PersonsEdit: TEdit
LCGrid: TStringGrid
ColCount = 2
FixedCols = 0
UpdateButton: TButton
Caption = Обновить
OKButton: TButton
Caption = Закрыть
4. Создать обработчики событий для компонентов формы, определить глобальные переменные, подключить необходимые библиотеки. Тексты модулей для форм приводятся в нижеследующих листингах.
4.1. Листинг модуля MainUnit:
unit MainUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, Grids, DBGrids, Menus, DB, ADODB, FoodUnit, RecipeUnit,
ComponentUnit, ListCalcUnit;
type
TMainForm = class(TForm)
FoodGrid: TDBGrid;
Splitter1: TSplitter;
RecipesGrid: TDBGrid;
Splitter2: TSplitter;
ComponentsGrid: TDBGrid;
CookBookMenu: TMainMenu;
CookBookConnection: TADOConnection;
N1: TMenuItem;
N2: TMenuItem;
N3: TMenuItem;
OpenDBItem: TMenuItem;
CloseDBItem: TMenuItem;
N5: TMenuItem;
ExitItem: TMenuItem;
NewRecipeItem: TMenuItem;
EditRecipeItem: TMenuItem;
NewFoodItem: TMenuItem;
EditFoodItem: TMenuItem;
N4: TMenuItem;
ListCalcItem: TMenuItem;
OpenDBDialog: TOpenDialog;
FoodTable: TADOTable;
RecipesQuery: TADOQuery;
RecipesDataSource: TDataSource;
ComponentsDataSource: TDataSource;
FoodDataSource: TDataSource;
RFLinksTable: TADOTable;
ComponentsQuery: TADOQuery;
AddFoodItem: TMenuItem;
RemoveFoodItem: TMenuItem;
EditQuantityItem: TMenuItem;
DeleteFoodItem: TMenuItem;
DeleteRecipeItem: TMenuItem;
CategoryTable: TADOTable;
RecipesTable: TADOTable;
procedure OpenDBItemClick(Sender: TObject);
procedure ComponentsSync(RID: Integer);
procedure RecipesQueryAfterScroll(DataSet: TDataSet);
procedure CloseDBItemClick(Sender: TObject);
procedure NewFoodItemClick(Sender: TObject);
procedure EditFoodItemClick(Sender: TObject);
procedure DeleteFoodItemClick(Sender: TObject);
procedure NewRecipeItemClick(Sender: TObject);
procedure EditRecipeItemClick(Sender: TObject);
procedure DeleteRecipeItemClick(Sender: TObject);
procedure AddFoodItemClick(Sender: TObject);
procedure RemoveFoodItemClick(Sender: TObject);
procedure EditQuantityItemClick(Sender: TObject);
procedure ListCalcItemClick(Sender: TObject);
procedure ExitItemClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
procedure TMainForm.ComponentsSync(RID: Integer);
begin
with ComponentsQuery do
begin
Close;
SQL.Clear;
SQL.Add('select RF_Links.ID, F_Name, Quantity');
SQL.Add('from Food, Recipes, RF_Links ');
SQL.Add('where Recipe_ID='+IntToStr(RID));
SQL.Add('and Food_ID=Food.ID');
SQL.Add('and Recipe_ID=Recipes.ID');
SQL.Add('order by Quantity desc');
Open;
end;
end;
procedure TMainForm.OpenDBItemClick(Sender: TObject);
begin
if (OpenDBDialog.Execute) then
begin
CookBookConnection.ConnectionString:=
'Provider=Microsoft.Jet.OLEDB.4.0;Data Source='+
OpenDBDialog.FileName;
if CookBookConnection.Connected then
begin
ShowMessage('База уже открыта’);
Exit;
end;
CookBookConnection.Open;
RecipesQuery.Open;
RFLinksTable.Open;
FoodTable.Open;
CategoryTable.Open;
RecipesTable.Open;
ComponentsSync(RecipesQuery.FieldValues['id']);
end;
end;
procedure TMainForm.RecipesQueryAfterScroll(DataSet: TDataSet);
begin
if RFLinksTable.Active and ComponentsQuery.Active then
ComponentsSync(RecipesQuery.FieldValues['id']);
end;
procedure TMainForm.CloseDBItemClick(Sender: TObject);
begin
CookBookConnection.Close;
end;
procedure TMainForm.NewFoodItemClick(Sender: TObject);
begin
with FoodForm do
begin
Caption:='Новый продукт;
NameEdit.Clear;
EnergyEdit.Clear;
PriceEdit.Clear;
if ShowModal=mrOK then
with FoodTable do
begin
Append;
FieldValues['F_Name']:=NameEdit.Text;
FieldValues['Energy']:=StrToFloat(EnergyEdit.Text);
FieldValues['Price']:=StrToFloat(PriceEdit.Text);
Post;
end;
end;
end;
procedure TMainForm.EditFoodItemClick(Sender: TObject);
begin
with FoodForm do
begin
Caption:=’Изменение продукта’;
NameEdit.Text:=FoodTable.FieldValues['F_Name'];
EnergyEdit.Text:=FoodTable.FieldValues['Energy'];
PriceEdit.Text:=FoodTable.FieldValues['Price'];
if ShowModal=mrOK then
with FoodTable do
begin
Edit;
FieldValues['F_Name']:=NameEdit.Text;
FieldValues['Energy']:=StrToFloat(EnergyEdit.Text);
FieldValues['Price']:=StrToFloat(PriceEdit.Text);
Post;
end;
end;
end;
procedure TMainForm.DeleteFoodItemClick(Sender: TObject);
begin
if (MessageBox(Handle, ‘Удалить продукт?’,
‘Удаление продукта’, MB_YESNO)=IDYES) then
FoodTable.Delete;
end;
procedure TMainForm.NewRecipeItemClick(Sender: TObject);
var i: Integer;
cids: array of Integer;
begin
with RecipeForm do
begin
Caption:='Новый рецепт';
NameEdit.Clear;
PersonsEdit.Clear;
CategoryCombo.Clear;
CategoryTable.First;
SetLength(cids, CategoryTable.RecordCount);
for i:=0 to CategoryTable.RecordCount-1 do
begin
CategoryCombo.Items.Add(CategoryTable.FieldValues['C_Name']);
cids[i]:=CategoryTable.FieldValues['ID'];
CategoryTable.Next;
end;
if ShowModal=mrOK then
with RecipesTable do
begin
Append;
FieldValues['R_Name']:=NameEdit.Text;
FieldValues['Persons']:=StrToFloat(PersonsEdit.Text);
FieldValues['Category_ID']:=cids[CategoryCombo.ItemIndex];
Post;
end;
end;
RecipesQuery.Requery;
Finalize(cids);
end;
procedure TMainForm.EditRecipeItemClick(Sender: TObject);
var i: Integer;
cids: array of Integer;
begin
with RecipeForm do
begin
Caption:='Изменение рецепта';
NameEdit.Text:=RecipesQuery.FieldValues['R_Name'];
PersonsEdit.Text:=RecipesQuery.FieldValues['Persons'];
CategoryCombo.Clear;
CategoryTable.First;
SetLength(cids, CategoryTable.RecordCount);
for i:=0 to CategoryTable.RecordCount-1 do
begin
CategoryCombo.Items.Add(CategoryTable.FieldValues['C_Name']);
cids[i]:=CategoryTable.FieldValues['ID'];
if (CategoryTable.FieldValues['ID']=
RecipesQuery.FieldValues['Category_ID']) then
CategoryCombo.ItemIndex:=i;
CategoryTable.Next;
end;
if ShowModal=mrOK then
with RecipesTable do
begin
Locate('ID', RecipesQuery.FieldValues['ID'], []);
Edit;
FieldValues['R_Name']:=NameEdit.Text;
FieldValues['Persons']:=StrToFloat(PersonsEdit.Text);
FieldValues['Category_ID']:=cids[CategoryCombo.ItemIndex];
Post;
end;
end;
RecipesQuery.Requery;
Finalize(cids);
end;
procedure TMainForm.DeleteRecipeItemClick(Sender: TObject);
begin
RecipesTable.Locate('ID', RecipesQuery.FieldValues['ID'], []);
RecipesTable.Delete;
RecipesQuery.Requery;
end;
procedure TMainForm.AddFoodItemClick(Sender: TObject);
begin
with ComponentForm do
begin
Caption:='Добавление продукта';
QuantityEdit.Clear;
if ShowModal=mrOK then
begin
with RFLinksTable do
begin
Append;
FieldValues['Recipe_ID']:=RecipesQuery.FieldValues['ID'];
FieldValues['Food_ID']:=FoodTable.FieldValues['ID'];
FieldValues['Quantity']:=QuantityEdit.Text;
Post;
end;
end;
end;
ComponentsQuery.Requery;
end;
procedure TMainForm.RemoveFoodItemClick(Sender: TObject);
begin
RFLinksTable.Locate('ID', ComponentsQuery.FieldValues['ID'], []);
RFLinksTable.Delete;
ComponentsQuery.Requery;
end;
procedure TMainForm.EditQuantityItemClick(Sender: TObject);
begin
with ComponentForm do
begin
Caption:='Изменение количества';
QuantityEdit.Text:=ComponentsQuery.FieldValues['Quantity'];
if ShowModal=mrOK then
begin
with RFLinksTable do
begin
Locate('ID', ComponentsQuery.FieldValues['ID'], []);
Edit;
FieldValues['Recipe_ID']:=RecipesQuery.FieldValues['ID'];
FieldValues['Food_ID']:=FoodTable.FieldValues['ID'];
FieldValues['Quantity']:=QuantityEdit.Text;
Post;
end;
end;
end;
ComponentsQuery.Requery;
end;
procedure TMainForm.ListCalcItemClick(Sender: TObject);
var i: Integer;
begin
with ComponentsQuery do
begin
lcp:=RecipesQuery.FieldValues['Persons'];
SetLength(lc, RecordCount);
First;
ListCalcForm.Caption:='Смета на '+IntToStr(lcp)+' персон';
ListCalcForm.LCGrid.ColWidths[0]:=200;
ListCalcForm.LCGrid.ColWidths[1]:=100;
ListCalcForm.LCGrid.RowCount:=lcp+1;
ListCalcForm.LCGrid.Cells[0, 0]:='Продукт';
ListCalcForm.LCGrid.Cells[1, 0]:='Количество';
for i:=0 to RecordCount-1 do
begin
ListCalcForm.LCGrid.Cells[0, i+1]:=FieldValues['F_Name'];
ListCalcForm.LCGrid.Cells[1, i+1]:=IntToStr(FieldValues['Quantity']);
lc[i]:=FieldValues['Quantity'];
Next;
end;
end;
ListCalcForm.ShowModal;
Finalize(lc);
end;
procedure TMainForm.ExitItemClick(Sender: TObject);
begin
Close;
end;
end.
4.2. Листинг модуля FoodUnit:
unit FoodUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TFoodForm = class(TForm)
NameEdit: TEdit;
Label1: TLabel;
PriceEdit: TEdit;
Label2: TLabel;
EnergyEdit: TEdit;
Label3: TLabel;
CancelButton: TButton;
OKButton: TButton;
procedure OKButtonClick(Sender: TObject);
procedure CancelButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
FoodForm: TFoodForm;
implementation
{$R *.dfm}
procedure TFoodForm.OKButtonClick(Sender: TObject);
begin
ModalResult:=mrOK;
end;
procedure TFoodForm.CancelButtonClick(Sender: TObject);
begin
ModalResult:=mrCancel;
end;
end.
4.3. Листинг модуля RecipeUnit:
unit RecipeUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TRecipeForm = class(TForm)
NameEdit: TEdit;
Label1: TLabel;
PersonsEdit: TEdit;
Label2: TLabel;
Label3: TLabel;
CategoryCombo: TComboBox;
CancelButton: TButton;
OKButton: TButton;
procedure CancelButtonClick(Sender: TObject);
procedure OKButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
RecipeForm: TRecipeForm;
implementation
{$R *.dfm}
procedure TRecipeForm.CancelButtonClick(Sender: TObject);
begin
ModalResult:=mrCancel;
end;
procedure TRecipeForm.OKButtonClick(Sender: TObject);
begin
ModalResult:=mrOK;
end;
end.
4.4. Листинг модуля ComponentUnit:
unit ComponentUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TComponentForm = class(TForm)
QuantityEdit: TEdit;
Label1: TLabel;
CancelButton: TButton;
OKButton: TButton;
procedure OKButtonClick(Sender: TObject);
procedure CancelButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
ComponentForm: TComponentForm;
implementation
{$R *.dfm}
procedure TComponentForm.OKButtonClick(Sender: TObject);
begin
ModalResult:=mrOK;
end;
procedure TComponentForm.CancelButtonClick(Sender: TObject);
begin
ModalResult:=mrCancel;
end;
end.
1.1. Листинг модуля ListCalcUnit:
unit ListCalcUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids, Math;
type
TListCalcForm = class(TForm)
OKButton: TButton;
Label1: TLabel;
PersonsEdit: TEdit;
UpdateButton: TButton;
LCGrid: TStringGrid;
procedure OKButtonClick(Sender: TObject);
procedure UpdateButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
ListCalcForm: TListCalcForm;
lc: array of Real;
lcp: Integer;
implementation
{$R *.dfm}
procedure TListCalcForm.OKButtonClick(Sender: TObject);
begin
ModalResult:=mrOK;
end;
procedure TListCalcForm.UpdateButtonClick(Sender: TObject);
var c: Real;
i: Integer;
begin
c:=StrToInt(PersonsEdit.Text)/lcp;
LCGrid.RowCount:=Length(lc)+1;
for i:=0 to Length(lc)-1 do
begin
lc[i]:=RoundTo(lc[i]*c, -2);
LCGrid.Cells[1, i+1]:=FloatToStr(lc[i]);
end;
lcp:=StrToInt(PersonsEdit.Text);
end;
end.
Содержание отчета
Программа с учетом основных рекомендаций.
Вопросы для самопроверки
1. Опишите схему получения клиентским приложением данных из БД с помощью технологии ADO.
2. Какие способы доступа к полям таблицы посредством компонента TADOTable вы знаете?
3. Что произойдет при удалении записи из таблицы продуктов, если ссылка на этот продукт присутствует в связанной таблице рецептов?
4. Зачем необходимо использовать метод Post при записи в таблицу?
5. В чем состоит необходимость использования метода Requery в тексте листингов?
Лабораторная работа № 6