- •Работа с типизированными файлами.
- •Варианты заданий
- •Теоретические сведения, необходимые для выполнения курсовой работы
- •1. Система программирования Delphi
- •2. Основные свойства компонентов
- •3. События компонентов
- •4. Компоненты Delphi
- •5. Работа с формами
- •6. Пример обработки исключительных ситуаций
- •7. Пример реализации приложения
7. Пример реализации приложения
Пусть требуется хранить следующую информацию о лицах: Фамилия, Имя, Возраст. Запрос: подсчитать средний возраст всех лиц.
Создадим новый проект приложения. На главной форме (назовем ее Main – в свойстве Name) разместим компонент MainMenu с пунктами: «Файл» (Открыть, Сохранить, Сохранить как…, Выход), и «Поиск». Также разместим StringGrid и кнопки «Добавить», «Удалить», «Изменить».
Настроим компонент StringGrid. Свойство FixedRow = 1 (фиксированное число строк для заголовков), FixedCols = 0, ColCount = 4 (Количество столбцов - Фамилия, Имя, Пол, Возраст). В составном свойстве Options установим goEditing = False (запретим ручное редактирование в таблице), goRowSelect = True (разрешим выделение всей строки).
Кнопки «Изменить» и «Добавить» первоначально сделаем недоступными (свойство Enabled = False).
Главная форма на этапе проектирования приложения представлена на рис. 1.
Рис. 1. Главная форма на этапе проектирования
С событием OnShow для формы свяжем следующий код:
procedure TMain.FormShow(Sender: TObject);
begin
//Задаем заголовки столбцов
StringGrid1.Cells[0,0]:='Фамилия';
StringGrid1.Cells[1,0]:='Имя';
StringGrid1.Cells[2,0]:='Пол';
StringGrid1.Cells[3,0]:='Возраст';
Kol:=0;
Nomer:=1;
end;
После запуска приложения (F9) форма примет следующий вид (рис.2):
Рис. 2. Главная форма на этапе выполнения приложения
Опишем необходимые переменные в модуле главной форме (Unit1).
Type
Zap = Record //описание записи
Fam: String[20];
Name: String[15];
Pol: Char;
Age: 18..60;
End;
Var
F: File of Zap; //описание типизированного файла
Rec: Zap;
Nomer: Integer; //номер редактируемой строки
I: integer;
Kol: integer; // количество записей
S: integer; // сумма всех возрастов
Sr: Real; //средний возраст
add: boolean;//признак нажатия кнопки «Добавить»
Для доступа к конкретному элементу записи используется следующая конструкция:
Zap.Fam:=’Иванов’;
Или с оператором присоединения (With):
With Zap do
begin
Fam:=’Сидоров’;
Name:=’Сидор’;
Pol:=’м’;
Age:=20;
end;
При нажатии кнопок «Добавить» и «Изменить» должно открываться окно для добавления/редактирования записи (назовем его EditRecord). Свойство BorderStyle (рамка формы) желательно установить равным bsDialog.
Компоненты ввода связываются с конкретными полями записи. Разместим на форме Label, Edit, SpinEdit (страница Samples) RadioGroup, две кнопки.
Пример формы ввода/корректировки (рис. 3):
Рис. 3. Форма редактирования на этапе проектирования приложения
Для компонента SpinEdit, содержащего информацию о возрасте, установим максимальное (MaxValue=60) и минимальное значение (MinValue=18), Value = 18 (текущее значение), EditorEnabled = False (значение будет только выбираться).
Для компоненты RadioGroup зададим свойства Caption, Items («мужской» и «женский» – должны располагаться в разных строках), ItemIndex = 0 (включенный переключатель. Нумерация с нуля. Значение «-1» означает, что никакой переключатель не выбран). Можно также использовать компонент ComboBox.
Если в главной форме была нажата кнопка «Добавить», то все элементы ввода должны очиститься, если «Изменить» - заполниться значениями изменяемой записи.
Реакция на нажатие кнопки «Добавить»:
procedure TMain.Button1Click(Sender: TObject);
begin
Edit_Record.Caption:='Добавление записи';//Меняем заголовок
add:=true;
Edit_Record.ShowModal;//Вызываем форму Edit_Record
end;
Реакция на нажатие кнопки «Изменить»:
procedure TMain.Button2Click(Sender: TObject);
begin
Edit_Record.Caption:='Изменение записи';//Меняем заголовок
add:=false;
Edit_Record.ShowModal;//Вызываем форму Edit_Record
end;
При отображении формы Edit_Record сделаем необходимые действия (для события OnShow):
procedure TEdit_Record.FormShow(Sender: TObject);
begin
if add=true then //была нажата кнопка "Добавить"
begin
//Очищаем поля ввода
Edit_Record.Edit1.Text:='';
Edit_Record.Edit2.Text:='';
//Задаем значения по умолчанию
Edit_Record.SpinEdit1.Value:=18;
Edit_Record.RadioGroup1.ItemIndex:=0;
end else //нажали кнопку "Изменить"
begin
//необходимо занести поля выделенной записи в элементы ввода
Edit1.Text:=Main.StringGrid1.Cells[0,Nomer];
Edit2.Text:=Main.StringGrid1.Cells[1,Nomer];
SpinEdit1.Value:=StrToInt(Main.StringGrid1.Cells[3,Nomer]);
//StrToInt - преобразует строковый аргумент в целое число
if Main.StringGrid1.Cells[2,Nomer]='м' then
RadioGroup1.ItemIndex:=0 else RadioGroup1.ItemIndex:=1;
end;
end;
Реакция на нажатие кнопки «ОК» на форме редактирования Edit_Record:
procedure TEdit_Record.Button1Click(Sender: TObject);
var d:integer;
begin
//добавляем в таблицу строку, если была нажата кнопка "Добавить"
if add then
begin
Kol:=Kol+1;
Main.StringGrid1.RowCount:= Kol+1;
d:=Kol;
if kol>0 then begin
//Делаем доступными кнопки "Изменить" и "Удалить"
Main.Button2.Enabled:=True;
Main.Button3.Enabled:=True;
end;
end else d:=Nomer;
//Заносим введенные значения в таблицу
Main.StringGrid1.Cells[0,d]:=Edit1.Text;
Main.StringGrid1.Cells[1,d]:=Edit2.Text;
Main.StringGrid1.Cells[3,d]:=IntToStr(SpinEdit1.Value);
//IntToStr - преобразует целое значение в строковое
if RadioGroup1.ItemIndex=0 then Main.StringGrid1.Cells[2,d]:='м'
else Main.StringGrid1.Cells[2,Kol]:='ж';
Close;//Закрываем форму редактирования
end;
Реакция на нажатие кнопки «Отмена» на форме редактирования Edit_Record:
procedure TEdit_Record.Button2Click(Sender: TObject);
begin
Close;//закрываем форму
end;
В событии OnSelectCell для StringGrid, которое возникает при выборе строки таблицы, сохранить номер строки:
procedure TMain.StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer;
var CanSelect: Boolean);
begin
Nomer:=Arow; {сохраняем номер выделенной строки}
end;
Реакция на нажатие кнопки «Удалить»:
procedure TMain.Button3Click(Sender: TObject);
begin
if Kol<>0 then
BEGIN
for i:=Nomer to StringGrid1.RowCount-1 do
with StringGrid1 do begin
//сдвигаем строки
cells[0,i]:= cells[0,i+1];
cells[1,i]:= cells[1,i+1];
cells[2,i]:= cells[2,i+1];
cells[3,i]:= cells[3,i+1];
end;
Kol:=Kol-1;
if Kol<>0 then StringGrid1.RowCount:= Kol+1 else
begin
//Делаем недоступными кнопки "Изменить" и "Удалить"
Button2.Enabled:=False;
Button3.Enabled:=False;
end;
end;
end;
Теперь опишем сохранение и открытие файла записей. Для отображения стандартных диалоговых окон сохранения/открытия будем использовать компоненты SaveDialog и OpenDialog со страницы Dialogs, которые разместим на главной форме. В свойство Filter установим «Файл данных|*.dat». Умалчиваемое расширение файлов (DefaultExt) – «dat». В свойстве InitialDir можно задать начальный диск/каталог для открытия/сохранения файла.
Данные компоненты являются невизуальными (т.е. не отображаются при запуске приложения).
Для работы с файлами используются следующие стандартные подпрограммы:
AssignFile(F, FileName) – связывает файл FileName с файловой переменной F.
Reset(F) – открывает файл F для чтения.
RewriteFile(F) – создает новый файл F. Если создаваемый файл уже имеется, перезаписывает его.
Read(F, V1, V2, …) – чтение данных из файла F в переменные.
Write(F, V1, V2, ...) – запись значений переменных в файл F.
Seek(F, N:LongInt) – передвигает указатель файла на N-ю компоненту (N-целое выражение). Первая компонента имеет номер 0. Для того, чтобы расширить файл, следует передвинуть указатель в конец файла функцией Seek.
Seek (F, FileSize(F)) – возвращает число записей в файле F, то есть указывает номер следующей компоненты после последней.
CloseFile(F) – закрывает файл F.
DeleteFile(F) – удаляет файл F.
RenameFile(OldName, NewName) – переименовывает файл OldName на NewName.
Реакция на выбор пункта меню «Открыть»:
procedure TMain.N3Click(Sender: TObject);
var i:integer;
begin
if Opendialog1.Execute //если диалог выполнился
and FileExists(OpenDialog1.FileName) then //выбранный файл существует
begin
//связываем имя файла с файловой переменной
AssignFile(f,OpenDialog1.FileName);
Reset(f); //открываем файл
i:=0; //номер строки
while not eof(f) do begin //пока не конец файла
read(f,Rec); //читаем очередную запись
inc(i);
stringgrid1.cells[0,i]:=Rec.Fam;
stringgrid1.cells[1,i]:=Rec.Name;
stringgrid1.cells[2,i]:=Rec.Pol;
stringgrid1.cells[3,i]:=IntToStr(Rec.Age);
stringgrid1.RowCount:=i+1; //Увеличиваем количество строк
end;
kol:=i; //сохраняем прочитанное количество строк
closefile(f);//закрываем файл
end else ShowMessage('Файл не существует!')
end;
Реакция на выбор пункта меню «Сохранить»:
procedure TMain.N5Click(Sender: TObject);
var i:integer;
begin
if SaveDialog1.Execute then //если диалог выполнился
begin
assignfile(f,savedialog1.FileName);//связь файла с переменной
if FileExists(SaveDialog1.FileName) then
begin
if MessageDlg('Файл с таким именем уже существует. Перезаписать?', mtConfirmation,[mbYes,mbNo],0)=mrNo then exit; //Выход
end;
rewrite(f,savedialog1.FileName); //создание файла
i:=0;
while i<>StringGrid1.rowCount-1 do begin //пока I <>кол-ву строк
inc(i);//увеличиваем счетчик прочитанных строк
Rec.Fam:=stringgrid1.cells[0,i];
Rec.Name:=stringgrid1.cells[1,i];
Rec.Pol:=stringgrid1.cells[2,i][1];
Rec.Age:=StrToInt(stringgrid1.cells[3,i]);
write(f,Rec); //сохраняем строку в файл
end;
closefile(f); //закрываем строку
end;
end;
Для реализации запроса последовательно просмотрим все строки записей в таблице, суммируя возраст и подсчитывая количество строк. После деления суммы на количество получим средний возраст. Результат можно выдать в сообщении при помощи функции ShowMessage.
procedure TMain.N8Click(Sender: TObject);
begin
S:=0;
i:=0;
if Kol<>0 then
while i<>StringGrid1.RowCount-1 do
begin //пока I <>количеству строк
inc(i);//увеличиваем счетчик прочитанных строк
S:=S+StrToInt(stringgrid1.cells[3,i]);//суммируем возраст
end;
Sr:=S/I;
ShowMessage('Средний возраст='+FloatToStrF(Sr,ffGeneral,10,3));
end;
Если запрос должен возвращать несколько строк результата, то их можно отобразить на отдельной форме в StringGrid или заносить в ListBox/Memo (методы Clear – очищает список, Lines.Add (строка) – добавляет новую строку)
Рис. 4. отображает пример работающего приложения.
Рис. 4. Окно работающего приложения
На рис. 5 представлен результат запроса.
Рис. 5. Выдача сообщения с результатом запроса