Редактирование и добавление записей
Для редактирования и добавления записей создадим окно, показанное на рис. 15.11.
Режим редактирования отличается от режима добавления записей двумя обстоятельствами: во-первых, в режиме редактирования поля ввода данных окна должны содержать текст, взятый из редактируемой записи, а в режиме ввода эти поля пусты. Во-вторых, режим редактирования завершается сразу после нажатия на клавишу Enter, в то время как в режиме ввода нажатие на эту клавишу означает добавление к файлу текущей записи и переход к вводу следующей: режим ввода завершается командой cmClose (клавиша Esc). С учетом этого оба режима реализуются в рамках одной процедуры AddItem (Edit), а параметр Edit указывает нужный режим: если Edit = True, реализуется режим редактирования, если False - режим добавления записей. Вот текст этой процедуры:
Рис.15.11. Окно ввода/редактирования записей
Procedure AddItem(Edit: Boolean);
{Добавляет новый или редактирует старый элемент данных}
const
у = 1;
dy= 2;
L -= LName+LPhone+LAddr;
var
Data: DataType;
R: TRect;
InWin: PDialog;
BName,BPhone,BAddr: PInputLine;
Control: Word;
OldCount: Word;
s: String;
р: PString;
begin
Seek(DataFile,FileSize(DataFile));{Добавляем записи в конец файла}
repeat {Цикл ввода записей}
if Edit then {Готовим заголовок}
s := 'Редактирование:'
else
begin
Str(FileSize(DataFile)+1,s);
while Length(s) < 3 do
s := '0'+s;
s :- 'Вводится запись N '+s
end;
FillChar(Data,SizeOf(Data),' ');{Заполняем поля пробелами}
R.Assign(15,5,65,16) ;
InWin := New(PDialog, Init(R, s));{Создаем окно}
with InWin do
begin{Формируем окно:}
R.Assign(2,y+1,2+LName,y+2);
BName := New(PInputLine, Init(R,LName));
Insert(BName); {Поле имени}
R.Assign(2,y,2+LName,y+1);
Insert(New(PLabel,
Init(R, 'Имя',BName)));
R.Assign(2,y+dy+1,2+LPhone,y+dy+2);
BPhone := New(PInputLine, Init(R,LPhone));
Insert(BPhone); {Поле телефона}
R.Assign (2,y+dy, 2+LPhone,y+dy+1) ;
Insert (New(PLabel,.
Init(R, 'Телефон',BPhone)));
R.Assign(2,y+2*dy+1,2+LAddr,y+2*dy+2);
BAddr := New(PInputLine, Init(R,LAddr));
Insert(BAddr); {Поле адреса}
R.Assign(2,y+2*dy,2+LAddr,y+2*dy+1);
Insert(New(PLabel,
Init(R, 'Адрес',BAddr)));
{Вставляем две командные кнопки:}
R.Assign(2,y+3*dy+1,12,y+3*dy+3);
Insert(New(PButton,
Init(R, 'Ввести',cmOK,bfDefault)));
R.Assign(2+20,y+3*dy+1,12+20,y+3*dy+3);
Insert(New(PButton,
Init(R, 'Выход',cmCancel,bfNormal)));
SelectNext(False) {Активизируем первую кнопку}
end; {Конец формирования окна}
if Edit then with Data do
begin {Готовим начальный текст:}
р :=PS.At(Location); {Читаем данные из записи)
S:=p;
Name := copy(s,1,LName);
Phone:= copy(s,succ(LName),LPhone);
Addr := copy(s,succ(LName+LPhone),LAddr);
InWin.SetData(Data) {Вставляем текст в поля ввода}
end;
Control := DeskTop.ExecView(InWin); {Выполняем диалог}
if Control=cmOk then with Data do
begin
if Edit then
DeleteItem; {Удаляем старую запись}
Name := BName.Data;
Phone:= BPhone.Data;
Addr := BAddr.Data;
s[0] := chr(L) ;
FillChar(s[1],L,' ');
move(Name[1],s[1],Length(Name)) ;
move(Phone[1],s[succ(LName)],Length(Phone));
move(Addr[1],s[succ(LName+LPhone)],Length(Addr));
OldCount := PS.Count; {Прежнее количество записей}
РS.insert(NewStr(s)); {Добавляемв коллекцию}
{Проверяем добавление}
if OldCount <> РS.Count then
Write(DataFile,Data) {Да - добавляем в файл}
end
until Edit or (Control=cmCancel);
Draw
end; {AddItem}
Вначале указатель файла смещается в самый конец, подготавливая добавление записей (судя по всему, режим добавления будет использоваться гораздо чаще, чем режим редактирования). Затем формируется заголовок окна и само окно. Операторы
if Edit then with Data do
begin {Готовим начальный текст:}
.......
end;
готовят начальное состояние полей ввода в режиме редактирования. Оператор
InWin. SetData (Data)
помещает подготовленный текст в нужные поля. При обращении к процедуре SetData данные должны быть предварительно подготовлены в строгом соответствии с порядком создания диалоговых полей в окне и типом их данных. Поскольку в нашем случае формат данных в полях ввода окна совпадает с форматом файловых данных, мы можем использовать одну и ту же переменную как для работы с файлом, так и для установки начальных значений диалоговых полей.
В самом общем случае пользователь должен объявить новый тип, соответствующий формату помещаемых в окно данных, и использовать выражение этого типа в качестве параметра обращения к процедуре SetData. Например, если бы в нашем окне было предусмотрено только одно поле ввода «Телефон», то установку данных можно было бы осуществить таким оператором:
InWin. SetData (DataType . Phone)
где DataType.Phone - выражение типа String [LPhone].
Контроль за соответствием типа устанавливаемых данных порядку объявления и типу данных диалоговых полей полностью возлагается на программиста. В операторах
if Control=cmOk then with Data do
begin
.....
end
данные, полученные из диалогового окна, помещаются сначала в отсортированную коллекцию, а затем - в файл. С помощью оператора
if OldCount <>PS. Count then
проверяется изменение количества данных в коллекции (напомню, что в отсортированную коллекцию можно поместить только уникальную запись). Если количество записей в коллекции изменилось, значит новая запись не совпадает ни с одной из уже имеющихся и ее следует поместить в файл.
Операторы
if Edit then
DeleteItem; {Удаляем старую запись}
предварительно удаляют старую запись с помощью обращения к процедуре DeleteItem.