procedure Init(
var X, { Номер столбца в таблице }
Y, { Номер строки в таблице }
Nx, { Количество строк в таблице }
Ny, { Количество столбцов в таблице }
InitY { Номер начальной строки в таблице на экране }
:byte;
var Xpos { Массив координат столбцов }
:ColumnsPositionsArray;
var P { Массив записей в таблице }
:ProcessorArray);
...
procedure ReadTable;
var
Line, { Номер строки в таблице }
Column { Номер столбца в таблице }
:byte;
Field { Содержимое поля в виде строки }
:string;
F:Text; { Текстовый файл с таблицей }
S:string; { Строка текстового файла с таблицей }
begin
OpenTextFile('Table.txt',F,ReadFile);
for Line:=1 to InitY do ReadLn(F,S); { Пропустить шапку }
for Line:=1 to Ny do
begin
ReadLn(F,S);
for Column:=1 to Nx do
begin
{ Выделение поля из строки }
Field:=Copy(S,Xpos[Column]+1,Xpos[Column+1]-Xpos[Column]-3);
{ Распечатка содержимого поля на экране
(потом на этом месте должна быть процедура ввода поля) }
MoveCursor(Column,Line,InitY,Xpos); Write(Field);
end;
end;
end;
begin { Init }
ClrScr; { Очистить экран }
ReadTableForm; {Чтение формы таблицы из файла }
ReadTable; { Чтение таблицы из файла }
{Установка курсора в начало таблицы }
Y:=1; X:=1; MoveCursor(X,Y,InitY,Xpos);
end; { Init }
...
Как при вводе данных из файла, так и с клавиатуры, вводимые данные представлены в виде строки, поэтому есть необходимость преобразования данных из строки к типу, соответствующему тому или иному полю таблицы. Эти действия переданы процедуре «Ввод поля» (EnterField), взамен простой распечатки на экране монитора, как это было сделано на предыдущем этапе. Параметры, необходимые для работы процедуры, представлены в листинге 6.
На данную процедуру возложено выполнение многих функций:
а) получать строку данных из файла или вызывать ввод с клавиатуры (функция KeyBoardInput, которую на данном этапе не будем пока рассматривать подробно, а только представим формальное описание; кроме того, заметим, что логическая переменная KeyBoard будет определять, откуда процедура EnterField берет строку данных: или с клавиатуры, после вызова функции KeyBoardInput, или из файла в строке FileStr;
б) приводить строку к виду без начальных и конечных пробелов (процедура
DeleteSpaces);
в) сравнивать длину вводимой строки с шириной поля таблицы (функция LengthCompare);
г) преобразовывать данные из строкового типа в тип данных соответствующего поля ( процедуры StrToByte, StrToCorp, StrToWord, StrToReal, которые здесь использованы, но без описания и подробных объяснений, так как эти процедуры достаточно просты, хотя и обязательно должны содержать проверку правильности преобразования из строки в соответствующий тип);
д) выводить проверенные данные в виде строки на экран (при этом понадобится дополнительная процедура для вывода сообщения об ошибке Error, которая в свою очередь использует процедуру для выхода в строку, расположенную ниже таблицы GoToSpecialLine).
Листинг 6
{ Процедура ввода поля таблицы }
procedure EnterField(
{ П а р а м е т р ы п р о ц е д у р ы }
KeyBoard:boolean; { Ввод с клавиатуры или из файла }
P:ProcessorArray; { Массив записей }
R, { Номер строки }
C, { Номер столбца }
Ny, { Количество строк }
InitY:byte; { Начало таблицы на экране }
Xpos: { Координаты столбцов на экране}
ColumnsPositionsArray;
FileStr:string; { Строка из файла }
{ Л о к а л ь н ы е п е р е м е н н ы е в п р о ц е д у р е }
var i,StrLen:byte; S:string; E:boolean;
{ Процедура вывода курсора в специальную строку.
Используется при вводе с клавиатуры и выводе сообщений об ошибке } procedure GoToSpecialLine(LineNum:byte { Номер строки });
begin
{ Переход в строку под таблицей }
GotoXY(1,InitY+Ny+1+LineNum);
end;
{Функция ввода с клавиатуры }
function KeyBoardInput:string;
begin { KeyBoardInput }
KeyBoardInput:='Функция ввода с клавиатуры.';
end; { KeyBoardInput }
{Процедура вывода сообщения об ошибке }
procedure Error(
S:string; { Строка сообщения }
var Sf:string); {Строка ввода поля данных в таблице }
begin
Sf:=''; GoToSpecialLine(1); Write(' ',S); Delay(2000);
GoToSpecialLine(1); ClrEol; MoveCursor(C,R,InitY,Xpos);
end;
{Функция сравнения длины вводимой строки с шириной поля таблицы }
function LengthCompare(
C:byte; {Номер столбца таблицы }
S:string; {Введенная строка }
var StrLen:byte {Ширина поля в таблице })
: boolean;
begin
StrLen:=(Xpos[C+1]-Xpos[C]-3); LengthCompare:=(StrLen>=length(S)); end;
...
begin { основная часть процедуры EnterField }
{ Ввод строки или с клавиатуры, или из файла }
if KeyBoard then S:=KeyBoardInput else S:=FileStr;
DeleteSpaces; { Удаление пробелов в начале и в конце строки }
if S<>'' then { Если строка ввода не пустая }
begin
if LengthCompare(C,S,StrLen)
then { если длина строки не больше столбца }
begin
with P[R] do { Преобразования из строки в тип поля }
case C of { Выбор по номеру поля }
1: StrToByte(S,N); 2: StrToCorp(S,Corp);
3: StrToWord(S,Freq); 4: Notice := S;
5: StrToWord(S,Count); 6: StrToReal(S,Price);
7: StrToReal(S,Summ);
end;
if S<>'' then
begin { Если преобразование прошло без ошибок }
{ Вывод значения поля в виде строки на экран }
MoveCursor(C,R,InitY,Xpos);
while length(S)<StrLen do S:=' '+S; { Добавление пробелов }
Write(S); { Вывод строки }
end;
end
else { Если длина строки больше столбца }
Error('Длина строки ввода больше ширины столбца.',S); end;
{ Вернуть курсор в соответствующую ячейку таблицы }
MoveCursor(C,R,InitY,Xpos);
end; { Основная часть процедуры EnterField } …
Теперь процесс инициализации работы программы завершен, и пришла пора более подробного описания процедуры основного цикла работы программы (Run). Здесь основным является управление процессом работы и ввод данных с клавиатуры (функция KeyBoardInput).
Перед тем как перейти к разработке процедуры ввода данных с клавиатуры, придется сначала определить тип переменной для ввода. Для этого сначала заметим, что вводятся с клавиатуры команды и символы. Среди команд будем различать:
- команды управления курсором;
- команды завершения ввода или завершения выбора;
- команды редактирования строки ввода данных с клавиатуры;
- команды выхода или отказа.
Команды представим перечисляемым типом:
type
Commands=(
cmLeft, cmRight, cmUp, cmDown, { управление курсором }
cmEnter, { завершение ввода/выбора }
cmBackSpace,cmDelete, { редактирование строки }
cmExit, { выход или отказ }
cmEmpty { пустая команда });
Любое действие с клавиатурой определим как некоторое событие, описываемое переменной типа запись. Тип этой записи имеет два поля:
type
EventType=record { Тип события - это запись }
Key:char; { Какая клавиша нажата }
Command:Commands; {Какой команде соответствует нажатие этой клавиши } end;
Для получения события от клавиатуры предусмотрена процедура GetEvent, которая определяет событие по кодам нажатых клавиш и будет всегда использоваться, когда необходимо опросить клавиатуру.
Первое применение для процедуры GetEvent сделаем в процедуре Run, где будем принимать в цикле события до тех пор, пока не поступит команда выхода из программы cmExit, а также будем обрабатывать команды перемещения курсора по таблице, используя процедуру ExecutePositionCommand.
Листинг 7
{ Процедура получения события от клавиатуры }
procedure GetEvent(var Event:EventType);
var c:char;
begin
c:=ReadKey; { Прочитать код нажатой клавиши }
with Event do
begin
Command:=cmEmpty;
case ord(c) of { Определить команду по коду нажатой клавиши }
27:Command:=cmExit; 13:Command:=cmEnter; 8:Command:=cmBackSpace;
0:
begin
c:=ReadKey; { Выбор по клавишам, имеющим двойной код }
case ord(c) of
72:Command:=cmUp; { Вверх } 75:Command:=cmLeft; { Влево}
77:Command:=cmRight; {Вправо} 80:Command:=cmDown; {Вниз} 83:Command:=cmDelete; {Удалить}
end; {case}
end;
end; {case}
Key:=c; { Запомнить код нажатой клавиши }
end; {with}
end;
...
{ Основной цикл }
procedure Run ( { П а р а м е т р ы п р о ц е д у р ы }
X, {Номер столбца в таблице }
Y, {Номер строки в таблице }
Nx, {Количество строк в таблице }
Ny, {Количество столбцов в таблице }
InitY:byte; {Номер начальной строки в таблицы на экране }
Xpos:ColumnsPositionsArray; {Массив координат столбцов }
var P:ProcessorArray); { Массив записей в таблице }
{ Процедура выполнения команд перемещения курсора }
procedure ExecutePositionCommand(
{ П а р а м е т р ы п р о ц е д у р ы }
Com:Commands; {Команда для обработки }
var X,Y, {Текущие координаты }
MaxX,MaxY {Границы по координатам }
:byte);
begin
case Com of
cmLeft : if X>1 then dec(X); cmRight: if X<MaxX then inc(X);
cmUp : if Y>1 then dec(Y); cmDown : if Y<MaxY then inc(Y);
end;
end;
var E:EventType; {Локальная переменная процедуры Run }
begin {Run }
repeat
Getevent(E); { Принять событие от клавиатуры }
with E do
case Command of
cmLeft..cmDown: {Обработка команд перемещения курсора }
begin
ExecutePositionCommand(Command,X,Y,Nx,Ny);
MoveCursor(X,Y,InitY,Xpos); end;
end; {case}
until E.Command=cmExit;
end; { Run }
...
begin {Основная часть программы }
{ Инициализация }
Init(Col,Row,Ncol,Nrow,InitRow,ColPos,Processors);
{ Основной цикл (теперь уже с параметрами) }
Run(Col,Row,Ncol,Nrow,InitRow,ColPos,Processors);
Done; {Завершение работы }
end.
В процедуре Run при получении команды cmEnter будем переходить на процедуру ввода поля данных EnterField, в которой теперь необходимо определить функцию ввода данных с клавиатуры - KeyBoardInput.
{ Основной цикл }
procedure Run
...
case Command of
...
cmEnter:
EnterField(FromKeyBoard,P,Y,X,Ny,InitY,Xpos,'');
end; {case}
В функции KeyBoardInput надо также выполнить много действий, которые выделены в отдельные процедуры и функции (эти действия рассмотрим не сразу, а последовательно одно за другим):
- начальные значения для переменных и начальное местоположение курсора определяет процедура InitKeyBoardInput;
Листинг 8
{ Ф у н к ц и я в в о д а с к л а в и а т у р ы }
function KeyBoardInput:string;
{ Локальные переменные для функции KeyBoardInput }
var Ev:EventType; Si:string; X,Y:byte; Cor:Corporations;
{ Процедура определения начальных установок }
procedure InitKeyBoardInput;
begin { InitKeyBoardInput }
Ev.Command:=cmEmpty; { Команды нет }
Cor:=P[R].Corp; { Начальное значение для имени корпорации }
{ Вывод дополнительных сообщений }
GoToSpecialLine(2);
Write('<Enter> - принять изменения, <Esc> - отказ от изменений.');
GoToSpecialLine(1);
if C=2 { Во втором столбце - выбор вариантов }
then
begin
Write('Выбор значения клавишами стрелок ( <- -> ): ');
ClrEol; X:=WhereX; Y:=WhereY; Write(CorpName[Cor]);
end
else Write('Введите значение: ');
end; { InitKeyBoardInput }
- ввод поля выбором вариантов с использованием клавиш стрелок простая, не требующая дополнительных пояснений функция InputByRows;
Листинг 9
{ Функция ввода поля выбором вариантов клавишами стрелок }