Ресурсы модуля crt для управления экраном.
Управление экраном с помощью ресурсов модуля crt базируется на понятии «окно».
Окно - часть экрана прямоугольной формы. В момент получения программой управления весь экран считается окном 25x80 знакомест. Программист может определять на экране новые окна и управлять как цветом символов и фона окна, так и размещением информации в окне. Вывод информации в текстовом режиме осуществляется стандартными процедурами Write и WriteLn текущими цветом символа и цветом фона.
При выводе четыре символа интерпретируются особым образом:
#7 - звуковой сигнал;
#8 - перемещение курсора влево на один символ;
#10 - перемещение курсора на строку вниз (если курсор находился в последней строке, то содержимое экран «прокручивается» на строку вверх);
#13 - перемещение курсора в начало текущей строки.
Рис. 8.2. Текущее окно на экране и относительная адресация символа в окне
Процедуры начинают вывод с того места, где стоит курсор. Координаты курсора определяются относительно верхнего левого угла текущего окна (рис. 8.2). Для управления окнами и размещения в них информации модуль crt содержит следующие процедуры и функции.
1. Процедура Window(xl, у1, х2, y2:word) - определяет на экране окно. Местоположение и размеры окна определяются координатами верхнего левого (х1, у1) и нижнего правого (х2, у2) углов прямоугольника. Координаты текущего окна модуль crt хранит в специальных переменных:
WindMin, WindMax:word.
Откуда координаты текущего окна можно определить, применив функции 1о и hi, которые выделяют из слова младший и старший байты соответственно:
xl=Lo(WindMin) - координата х верхнего левого угла;
у1=Hi(WindMin) - координата у верхнего левого угла;
x2=Lo(WindMax) - координата х нижнего правого угла;
y2=Hi(WindMax) - координата у нижнего правого угла.
После объявления окна курсор устанавливается в верхний левый угол окна.
2. Процедура TextColor(color:byte) - устанавливает текущий цвет вывода символов в окне.
3. Процедура TextBackGround(color:byte) - устанавливает текущий цвет фона окна. Цвета для процедур TextColor и TextBackGround можно задавать, используя специальные константы модуля crt:
Black=0; {черный} DarkGrey=8; {темно-серый}
Blue=1; {синий} LightBlue=9; {светло-синий}
Green=2; {зеленый} LightGreen=10; {светло-зеленый}
Cyan=3; {голубой} LightCyan=11; {светло-голубой}
Red=4; {красный} LightRed=12; {розовый}
Magenta=5; {фиолетовый} LightMagenta=13; {сиреневый}
Brown=6; {коричневый} Yellow=14; {желтый}
LightGrey=7; {светло-серый} White=15; {белый}
Blink=128; {мерцание}
Текущие цвета символа и фона в виде байта атрибута хранятся в переменной TextAttr:word. Текущий цвет фона из этой переменной определяется как
(TextAttr div 16) mod 8,
a текущий цвет символа как
TextAttr mod 16.
4. Процедура ClrScr - очищает окно, выводя в него пробелы с текущим атрибутом. После этого курсор устанавливается в верхний левый угол окна. Если окно не установлено, то очищается весь экран. Эту процедуру обычно используют после определения окна и атрибута его символов, чтобы обозначить окно на экране.
5. Функция WhereX:word - возвращает координату х текущего положения курсора в окне.
6. Функция WhereY:word - возвращает координату у текущего положения курсора в окне.
7. Процедура GotoXY(x,y:word) - перемещает курсор на знакоместо с координатами x и у.
Модуль crt содержит также процедуры, работающие с текущей строкой (строкой, в которой стоит курсор).
8. Процедура DelLine - удаляет текущую строку.
9. Процедура InsLine - вставляет строку, сдвигая остальные строки вниз.
10. Процедура ClrEol – стирает часть строки справа от курсора.
Пример 8.1.
Разработать программу вычисления среднего арифметического заданного количества чисел n, где n<10. Реализовать оконный интерфейс, представленный на рис. 8.3. Верхнее окно интерфейса не зависит от исходных данных. Его нужно определить, задать цвета символов и фона, очистить и вывести в него текст. Ввод ответа пользователя будет выполняться с того места, где окажется курсор. Количество окон для ввода чисел зависит от введенного значения. Их положение на экране необходимо рассчитать.
Рис. 8.3. Интерфейс программы вычисления среднего арифметического
Нижнее окно также не зависит от исходных данных. Его нужно определить и внести в него результат. Ниже представлена соответствующая программа с комментариями.
Program ex;
Uses Crt;
Var a:array[1 10] of integer;
x,dx,n,i:integer; s:real;
Begin
ClrScr; {очищаем экран}
Window(20,3,50,5); {выделяем окно ввода количества чисел}
TextAttr:=16+7; {определяемсветло-серые символы на синем фоне}
ClrScr; { выделяем окно ввода}
GotoXY(2,2); {устанавливаем курсор для вывода запроса}
Write(‘введите количество чисел:’); {выводим запрос}
ReadLn(n); {вводим ответ пользователя}
dx:=(80-(n+1)*3)div n;
х:=0;
s:=0;
TextAttr:=2*I6+14; {желтые символы на зеленом фоне}
for i:=1 to n do
begin х:=х+3;
Window(x,7,x+dx,9); {устанавливаем окно ввода данных}
ClrScr; {выделяем это окно}
GotoXY(2,2);{устанавливаем курсор для ввода данных}
ReadLn(a[i]); {вводим число}
s:=s+a[i];
x:=x+dx;
end;
TextAttr:=4*16+14; {желтые символы на красном фоне}
Window(18,11,53,13); {устанавливаем окно результата}
ClrScr;{выделяем окно результата}
GotoXY(3,2);{устанавливаем курсор для вывода результата}
Write('Cpeднee арифметическое =’, s/n:5:2);
ReadLn; {ожидаем нажатия клавиши Enter}
Window(1,1,80,25); {восстанавливаем окно на весь экран}
TextAttr:=7; {восстанавливаем стандартные цвета}
ClrScr; {очищаем экран}
End.
Управление клавиатурой
Клавиатура - достаточно сложное устройство, в состав которого входит микропроцессор и память - буфер клавиатуры. При нажатии и отпускании любой клавиши в буфер клавиатуры записываются так называемые коды нажатия/отпускания, при этом микропроцессор клавиатуры отсекает дребезг клавиш - сигналы, полученные при неполном контакте в процессе нажатия и отпускания клавиши.
Клавиши клавиатуры делят на буквенно-цифровые, специальные и клавиши смещения.
К буквенно-цифровым относят клавиши букв, цифр, специальных знаков и пробела. Их используют для ввода информации.
Специальные клавиши - это клавиши управления курсором (←, ↑, →, ↓, Home, End, Tab, Page up. Page down), удаления (Del, Backspace), клавиши переключения режимов (Ins, Caps lock, Num lock, Scrool lock), функциональные клавиши (Esc, Break, Fl, F2, F3, ..., FI2) и т.д. Эти клавиши используют для выполнения вспомогательных операций во время работы с компьютером.
Клавиши смещения - это клавиши Shift, Ctrl и Alt. Их используют совместно с другими клавишами для изменения вводимых кодов. Так, если при нажатии клавиши «а» формируется код строчной буквы а латинского алфавита, то нажатие Shift-a приведет к вводу кода заглавной буквы А латинского алфавита.
Всего выделяют около 400 различных комбинаций, которые могут обрабатываться программой. Эти комбинации формируются на основании кодов нажатия/отпускания специальной программой BIOS (базовая система обработки ввода-вывода) и записываются в буфер BIOS клавиатуры.
Изначально считалось, что количество различных комбинаций не превысит 256, и, соответственно, для представления этой информации будет достаточно 1 байта (см. приложение 2), но со временем количество комбинаций возросло, и потребовалось использование второго байта.
В настоящее время для представления комбинаций, не вошедших в таблицу ASCII, используют расширенные коды, состоящие из двух байт: первый байт равен 0, а второй - содержит расширенный scan-код (см. приложение 3).
Ввод буквенно-цифровых данных с клавиатуры осуществляется процедурами Read и ReadLn,при этом реально происходит чтение кодов ASCII из буфера BIOS клавиатуры. Считанные символьные коды преобразуются во внутренний формат в соответствии с типом переменной.
Процедуры Read и ReadLn обрабатывают только комбинации, соответствующие буквам и цифрам, а также некоторые специальные комбинации, например, маркер конца строки (комбинация символов #13, #10).
Модуль crt содержит специальные функции управления клавиатурой, которые позволяют работать с расширенными кодами.
1. Функция KeyPressed: boolean - возвращает true, если нажата любая клавиша, false - если буфер BIOS клавиатуры пуст; функция не извлекает символы из буфера, не ожидает ввода;
2. Функция ReadKey:char - извлекает очередной код из буфера BIOS клавиатуры и возвращает его как результат операции, ожидает ввода, но не высвечивает вводимого символа.
Для чтения расширенного кода функцию ReadKey необходимо вызывать дважды: первый раз она вернет 0, а второй - расширенный scan-код:
chl:=ReadKey; {читаем код}
if chl=#0 then ch2:=ReadKey; {если код=0, то читаем второй байт}
Пример 8.2.Разработать программу определения кодов клавиш и их комбинаций. Выход из цикла осуществлять по нажатию клавиши Esc.
Program ex;
Uses crt;
Var c1,c2:char;
Begin
repeat c1:=ReadKey; {вводим код}
if c1=#0 then {если расширенный код}
begin
c2:=ReadKey; {то читаем расширенный scan-код}
WriteLn(ord(c1):5, ord(c2):5) {выводим расширенный код}
end
else WriteLn(ord(c1):5) {выводим код ASCII}
until c1 =#27;{до нажатия Esc}
End.
Таблица 8.2
Примечание. Функция ReadKey обрабатывает коды из буфера BIOS клавиатуры, поэтому с ее помощью нельзя получить коды нажатия/отпускания отдельных клавиш, не преобразуемых в расширенные scan-коды, например, клавиш смещения, клавиш переключения режимов.
Состояния клавиш смещения и клавиш переключения режимов BIOS фиксирует в байте состояния клавиатуры (табл. 8.2), который расположен в
оперативной памяти по адресу $0:$417.
Для прямого обращения к этому байту можно использовать стандартно объявленный массив Mem:array of byte, например: Mem[$0:$417], или наложить некоторую переменную на интересующий нас байт оперативной памяти:
Var KeyState:byte absolute $0:$417; … .
Управление динамиком
Модуль crt также содержит процедуры, обеспечивающие управление динамиком.
1. Процедура Sound (f:word) - генерирует звук указанной частоты в Гц.
Для справки, основной гамме соответствуют следующие частоты: нота «до» основной октавы - 330 Гц, далее - 349 Гц, 370 Гц, 392 Гц, 415 Гц, 440 Гц, 466 Гц, 494 Гц, 523 Гц, 554 Гц, 588 Гц, 622 Гц и, наконец, нота «до» следующей октавы - 660 Гц. Частоты нот других октав кратны частотам основной.
2. Процедура NoSound - выключает динамик.
3. Процедура Delaу (t:word) - обеспечивает задержку на заданный интервал времени, мс.
Поскольку к настоящему моменту времени быстродействие компьютеров существенно возросло и изменились некоторые принципы их построения, процедура Delay не всегда обеспечивает корректную задержку, как видно из последующей программы. В этих случаях для организации задержки целесообразно использовать процедуру, которая читает реальное время.
4. Процедура GetTime (VarHour, Minute, Second, Sec100:word) – возвращает текущее время суток. Определена в модуле Dos.
Пример 8.3.Разработать программу проигрывания основной октавы.
Проигрывание гаммы осуществляется включением и выключением динамика с разными частотами.
Program ex;
Uses Crt;
Const f: array[1..13] of word = (330, 349, 370, 392, 415, 440,
466, 494, 523, 554, 588, 622, 660);
Var i:byte;
Begin for i:=1 to 13 do
begin
Sound(f[i]);
for j:=1 to 5000 do Delay(1000);{задержка ?!}
NoSound;
end;
End.
Чтобы не подбирать время задержки для конкретного компьютера, построим свою процедуру обеспечения требуемой задержки, использующую процедуру GetTime:
Program ex;
Uses Crt, Dos;
Procedure NewDelay(dTime:word);
Var key:boolean;
Hour, Min, Sec, Sec100, MyHour, MyMin, MySec, MySec100: Word;
Begin
GetTime(Hour, Min, Sec, Sec100); {узнаем текущее время}
{определяем время завершения задержки}
MySec100:=Sec100+dTime; MySec:=Sec+MySecl00 div 100;
MySec100:=MySec100 mod 100;
MyMin:=Min+MySec div 60; MySec:=MySec mod 60;
MyHour:=Hour+MyMin div 60; MyMin:=MyMin mod 60;
key:=false;
while not key do {цикл задержки}
Begin
GetTime(Hour, Min, Sec, Sec100); {узнаем текущее время}
{проверяем, наступил ли заданный момент}
if (Ноиr>МуНоиr) or ((Ноиr=МуНоиr) and ((Min>MyMin) or
((Min=MyMin) and ((Sec>MySec) or
((Sec=MySec) and ((Sec100>=MySec100)))))))
then key:=true;
End
End;
Const farray[1..13] of word = (330, 349, 370, 392, 415, 440,
466, 494, 523, 554, 588, 622, 660);
Var i:byte; j:integer;
{описываем массив окон пунктов меню}
Const menu:array[1..4] of win=
((x1:5;y1:4;x2:15;y2:4;text: 'new '),
(x1:5;y1:5;x2:15;y2:5;text: 'open'),
(x1:5;y1:6;x2:15;y2:6;text: save'),
(x1:5;y1: 7;x2:15;y2:7;text: 'exit'));
{процедура рисования пункта меню}
Procedure DrawWin(w:win;attr:byte);
Begin
with w do
begin
TextAttr:=attr; {устанавливаем атрибут окна пункта}
Window(xl,у1,х2,у2); {устанавливаем окно пункта}
Clrscr; {высвечиваем окно пункта}
GotoXY(2,1); {устанавливаем курсор}
Write(text); {выводим название пункта}
end;
End;
{процедура рисования меню с выделенным пунктом npos}
Procedure DrawMenu(npos: integer);
Begin
Clrscr;
for i:=1 to 4 do
if i=npos then DrawWin(menu[i],94) {выводим выделенный пункт}
else DrawWin (menu[i], 30); {выводим невыделенный пункт}
End;
{основная программа}
Begin
npos:=1; {выделенный пункт меню}
DrawMenu(npos); {выводим меню}
repeat
ch1:=ReadKey; if ch1=#0 then ch2:=ReadKey;
case ch1 of
#0: case ch2 of
#72: begin {стрелка вверх}
if npos>1 then {если не верхний пункт}
begin
DrawWin(menu[npos],30); {убираем выделение текущего пункта меню}
npos:=npos-1; {переходим к предыдущему пункту}
DrawWin(menu[npos],94); {выделяем новый пункт}
end;
end;
Begin for i:=l to 13 do
begin
Sound(f[i]):
NewDelay(50);
NoSound;
end;
End.