Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Delphi_part2

.pdf
Скачиваний:
9
Добавлен:
01.03.2016
Размер:
951.59 Кб
Скачать

11.3.3 Определение типов данных

Для реализации проекта нужно определить тип записи, тип файла для хранения исходных данных и тип функции сравнения записей, используемый при сортировке. Эти описания должны быть доступны всем процедурам проекта, поэтому их следует расположить вне этих процедур, в начале раздела

Implementation.

Тексты этих описаний для создаваемого проекта приведены ниже.

implementation type

TName=String[20]; // Тип для фамилии студента // Тип для записей, которые содержит файл

TAttRec = record

 

Name: TName;

// Фамилия студента

ball: real;

// Средний балл успеваемости

neud: integer

// Количество неудоволетворительных оценок

end;

 

// Тип для файла

 

TAttFile = file of TAttRec;

// Тип для функции сравнения записей,

TCompareRec = function(r1, r2: TAttRec): boolean;

11.3.4 Настройка интерфейса пользователя

При запуске проекта необходимо подготовить интерфейс к работе. Для этого можно использовать процедуру обработки события onCreate формы. Именно эта процедура настроит компоненты StringGrid для вывода записей проекта. Исходный код процедуры приводится ниже.

// Настройка компонентов StringGrid procedure TfrmAtt.FormCreate(Sender: TObject); begin

with StringGrid1 do begin

ColCount := 3; RowCount := 2;

FixedCols := 0; FixedRows := 1; Cells[0,0] := 'Cтудент'; Cells[1,0] := 'Ср.балл'; Cells[2,0] := 'Неуд.';

81

end;

with StringGrid2 do begin

ColCount := 3; RowCount := 2; FixedCols := 0; FixedRows := 1; Cells[0,0] := 'Cтудент'; Cells[1,0] := 'Ср.балл'; Cells[2,0] := 'Неуд.';

end;

with StringGrid3 do begin

ColCount := 3; RowCount := 2; FixedCols :=0; FixedRows := 1; Cells[0,0] := 'Cтудент'; Cells[1,0] := 'Ср.балл'; Cells[2,0] := 'Неуд.';

end;

end;

В результате выполнения этой процедуры интерфейс пользователя должен приобрести вид, представленный на рисунке 11.3.

Рисунок 11.3 – Интерфейс проекта после настройки

82

11.3.5Вспомогательные процедуры для работы с файлом

11.3.5.1 Процедура выбора имени файла

Эта процедура должна вызываться при нажатии на кнопку «Имя файла». Для выбора имени используется компонент OpenDialog. Этот компонент открывает стандартное окно Windows для выбора имени файла при вызове функции Execute. Эта функция, помимо открытия окна, возвращает результат взаимодействия с пользователем в виде логической переменной. Если пользователь отказался от выбора файла, функция возвращает false, в противном случае – true. Кроме того, объект OpenDialog запоминает имя выбранного файла. Доступ к этому имени можно получить через свойство

FileName.

Ниже приведена процедура выбора имени файла.

//Процедура выбора имени файла

procedure TfrmAtt.btnFileNameClick(Sender: TObject); begin

if OpenDialog.Execute then EditFileName.Text := OpenDialog.FileName;

end;

В результате выполнения процедуры в поле EditFileName должно появиться выбранное имя файла.

11.3.5.2 Процедура открытия файла

Так как в проекте придется реализовать достаточно много подпрограмм, связанных с обработкой файла, то целесообразно группу инструкций, связанных с открытием файла вынести в отдельную процедуру.

В качестве параметра в процедуру передается файловая переменная типа TAttFile. Имя открываемого файла процедура считывает из поля EditFileName формы. Если файл существует, он открывается, если нет, то создается.

//Процедура открытия файла procedure openAttFile(var f:TAttFile); begin

assignFile(f, frmAtt.EditFileName.Text); try

reset(f); except rewrite(f);

83

end;

end;

11.3.5.3 Процедура вывода файла в StringGrid

Необходимость вывода файла в компонент TStringGrid в нашем проекте будет возникать неоднократно. Поэтому эту операцию целесообразно оформить как процедуру, которой в качестве параметра передается файловая переменная и ссылка на компонент TStringGrid.

//Процедура вывода файла в StringGrid

procedure showFileInGrid(var f: TAttFile; g: TStringGrid); var i:integer; r: TAttRec;

begin

//Настраиваем StringGrid g.RowCount:=fileSize(f)+1; i:=1; // счетчик строк StringGrid //Файл в начало

Reset(f);

//Организуем цикл по записям файла while not eof(f) do

begin

//читаем запись read(f,r);

//Переносим запись в StringGrid g.Cells[0, i]:=r.Name;

g.Cells[1, i]:= FloatToStr(r.ball); g.Cells[2, i]:= IntToStr(r.neud); i:=i+1;

end;

end;

11.3.6 Процедуры работы со StringGrid1

Эти процедуры используются для управления компонентом StringGrid1, который служит для подготовки записей перед занесением их в файл.

Первая из процедур связана с пунктом меню «Добавить строку».

// Добавление строки в StringGrid1

84

procedure TfrmAtt.mnuAddRowClick(Sender: TObject); begin

StringGrid1.RowCount := StringGrid1.RowCount + 1; end;

Вторая процедура связана с пунктом меню «Удалить строку». Удаление строки производится циклическим сдвигом записей на место удаляемой.

//Удаление строки из StringGrid1

procedure TfrmAtt.mnuDelRowClick(Sender: TObject); var i, j:integer;

begin

with StringGrid1 do begin

for i:=Row to RowCount - 2 do

for j:=0 to ColCount-1 do Cells[j,i]:= Cells[j, i+1]; RowCount := RowCount -1;

end;

end;

11.3.7 Процедуры реализации пунктов меню fileMenu

11.3.7.1 Добавление данных из StringGrid1 в файл

Эта процедура должна быть связана с пунктом меню «Добавить в файл из

StringGrid1».

// Добавление данных из StringGrid1 в файл

procedure TfrmAtt.mnuAddToFileClick(Sender: TObject); var f: TAttFile; i: integer; r: TAttRec;

begin

//Открываем файл openAttFile(f);

//Переходим в конец файла seek(f, FileSize(f));

// Дописываем записи из StringGrid1 for i := 1 to StringGrid1.RowCount - 1 do begin

85

r.Name := StringGrid1.Cells[0,i];

r.ball := strToFloat(StringGrid1.Cells[1,i]); r.neud := strToInt(StringGrid1.Cells[2,i]); write(f, r);

end;

showMessage('Данные записаны'); showFileInGrid(f, StringGrid2);

//закрываем файл closeFile(f);

end;

11.3.7.2 Поиск записи по фамилии

Эта процедура должна быть связана с пунктом меню «Поиск записи по фамилии».

// Поиск записи по фамилии

procedure TfrmAtt.mnuFindFamClick(Sender: TObject); var fam:TName; r:TAttRec; ok:boolean; f:TAttFile;

begin

fam := inputBox('Поиск записи по фамилии', 'Введите фамилию', '');

//Открываем файл openAttFile(f);

//Организуем цикл по записям файла ok:=false; // Признак того, что запись найдена while not eof(f) do

begin

// Читаем запись read(f,r);

if r.Name = fam then begin

showMessage( 'Результаты аттестации ' + fam + #13 + 'Ср.балл = ' + floatToStr(r.ball) + #13 + 'Количество неуд = ' + intToStr(r.neud));

ok := true;

break; // Прерываем цикл когда нашли

end;

86

end;

if not ok then showMessage(fam + ' не найдено'); end;

11.3.7.3 Удаление записи по фамилии

Эта процедура должна быть связана с пунктом меню «Удаление записи по фамилии».

//Удалить запись из файла

procedure TfrmAtt.mnuDelFamClick(Sender: TObject);

var fam: TName; r: TAttRec; f: TAttFile; pos: integer; ok :boolean; begin

fam:=inputBox('Удаление записи из файла','Введите фамилию','');

// Открываем файл openAttFile(f);

ok := false; // Признак того, что нужная запись найдена // Организуем цикл по записям файла

while not eof(f) do begin

// Читаем запись read(f,r);

if r.Name = fam then begin

//Нашли нужную ok := true;

//Запоминаем номер найденной записи (она уже предыдущая) pos := filePos(f) - 1;

//читаем последнюю запись seek(f,FileSize(f)-1); read(f,r);

//Записываем последнюю на место удаляемой seek(f,pos);

write(f,r);

//удаляем последнюю seek(f,FileSize(f)-1); truncate(f);

87

showMessage('Запись удалена ');

// Выводим измененный файл в StringGrid2 showFileInGrid(f,StringGrid2);

end;

end;

if not ok then showMessage(fam+' не найдено'); closeFile(f);

end;

11.3.7.4 Сохранение файла под другим именем

Эта процедура должна быть связана с пунктом меню «Сохранение файла под другим именем».

// Сохранение файла под другим именем

procedure TfrmAtt.mnuSaveAsClick(Sender: TObject); var f1,f2:TAttFile; r:TAttRec; f2Name:String;

begin

// Запрашиваем через SaveDialog новое имя файла для сохранения if SaveDialog.Execute then

begin

// Новое имя файла

f2Name := SaveDialog.FileName;

//Открываем файл в который будем переписывать

AssignFile(f2, f2Name); Rewrite(f2);

//Открываем файл, имя которого записано в EditFileName openAttFile(f1);

//Цикл копирования записей из f1 в f2

while not eof(f1) do begin read(f1,r); write(f2,r);

end;

CloseFile(f2);

CloseFile(f1);

88

ShowMessage('Файл скопирован в ' + f2Name); end;

end;

11.3.8 Процедуры для работы с упорядоченными файлами

11.3.8.1 Процедура сортировки файла

Алгоритмы сортировки файлов подобны алгоритмам сортировки массивов. Но особенность состоит в том, что при обращении к нужной записи в файле приходится вызывать процедуру seek(), кроме того, приходится учитывать, что файловая позиция смещается после выполнения операции чтения или записи.

Ниже приведена процедура пузырьковой сортировки по фамилии студента для открытого файла записей с результатами аттестации. Так как сортировку записей можно производить и по другим признакам, например, по баллу, но в этом случае в процедуре нужно заменить выражение для сравнения записей.

Внешний цикл сортировки такой же, как и для массива, а во внутреннем цикле последовательно считываются две записи файла и сравниваются. Если порядок их следования нарушен, они записываются в обратном порядке.

//Пузырьковая сортировка файла по фамилии студента procedure sortAttFile(var f: TAttFile);

var i, k: integer; ri1, ri2: TAttRec; ok: boolean; begin

k := FileSize(f)-1; repeat

ok := true; k := k - 1;

for i := 0 to k do begin

//Переходим на i-ю запись seek(f,i);

//Читаем две подряд идущих записи read(f,ri1);

read(f,ri2);

//сравниваем эти записи if ri1.name > ri2.name then

89

begin

//Записываем в обратном порядке seek(f,i);

write(f,ri2);

write(f,ri1);

ok:=false;

end;

end; until ok;

end;

11.3.8.2 Поиск записи в отсортированном файле

Для поиска записи в упорядоченном файле можно метод дихотомии, который рассматривался при поиске в упорядоченном массиве.

function findPosInSortFile(fam: TName; var f: TAttFile): integer; var pos, left, right: integer; r: TAttRec;

begin

result := -1; // Если элемент не будет найден //Начальные значения левой и правой границ left := 0; right := FileSize(f)-1;;

while left <= right do begin //Ищем, пока left не правее right // Находим индекс середины массива

pos := (right+left)div 2; seek(f, pos);

read(f, r);

if fam = r.Name then begin

//Элемент найден, и мы выходим из подпрограммы result := pos;

exit;

 

end;

 

if fam < r.Name

 

then right := pos – 1

// Будем искать левее

else left := pos+1;

// Будем искать правее

end;

 

90

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]