Pers.narod.ru. Обучение. Учебник по Паскалю. Глава 24 |
Модуль crt содержит процедуры и функции, предназначенные для работы с экраном консоли в текстовом режиме. Как и ряд других стандартных модулей, crt встроен в компилятор и содержится в файле turbo.tpl.
Экран в текстовом режиме разбивается на отдельные строки, а каждая строка -- на позиции, причем в каждую позицию может быть помещен только 1 символ из набора ASCII.
Для полного описания экранной позиции кроме символа следует задать еще и атрибут, содержащий информацию о цвете символа и фона на экране. Символ и атрибут занимают в памяти по 1 байту. Структура байта-атрибута показана на рис. 24.1.
Рис. 24.1. Структура байта-атрибута консоли
Старший бит 7 управляет мерцанием символа (символ на экране мерцает, если он установлен в 1), биты 4-6 содержат цвет фона (кодируется двоичными числами от 0 до 7 включительно), а биты 0-3 -- цвет символа (от 0 до 15). Разумеется, программисту обычно не приходится заполнять байт атрибута по битам, для этого есть стандартные коды цветов. Основные цвета кодируются цифрами от 0 до 15, причем цвет текста может быть любым, а цвет фона -- только из первых 8 цветов. Все цвета описаны в табл. 24.1.
Табл. 24.1. Коды и наименования стандартных цветов
Код |
Наименование |
Цвет |
0 |
BLACK |
черный |
1 |
BLUE |
синий |
2 |
GREEN |
зеленый |
3 |
CYAN |
циановый |
4 |
RED |
красный |
5 |
MAGENTA |
фиолетовый |
6 |
BROWN |
коричневый |
7 |
LIGHTGRAY |
светло-серый |
8 |
DARKGRAY |
темно-серый |
9 |
LIGHTBLUE |
голубой |
10 |
LIGHTGREEN |
светло-зеленый |
11 |
LIGHTCYAN |
светло-циановый |
12 |
LIGHTRED |
светло-красный |
13 |
LIGHTMAGENTA |
светло-фиолетовый |
14 |
YELLOW |
желтый |
15 |
WHITE |
белый |
Можно обращаться к цвету как по цифровому коду, так и по англоязычному имени.
Широко используемые текстовые режимы имеют в окне консоли 25 строк по 80 столбцов (позиций) в строке. Нумерация строк и позиций начинается с 1 и считается слева направо и сверху вниз. Весь экран в текстовом режиме может быть описан парой координат (1, 1), (80, 25). Обратите внимание на порядок записи -- столбец, затем строка.
Ниже рассмотрены основные процедуры и функции модуля. Везде для краткости введены следующие обозначения:
x,x1,x2 -- координаты столбцов экрана;
y,y1,y2 -- координаты строк экрана;
c -- значение цвета.
Особенность модуля crt состоит в том, что он позволяет работать не только со всем экраном, но и с выделенным на нем прямоугольным окном. При этом весь ввод, вывод и прокрутка текста происходят в пределах окна. По умолчанию размеры окна совпадают с размерами экрана, но можно явно установить их обращением к стандартной процедуре Window (x1,y1,x2,y2);, где (x1, y1) и (x2, y2) -- соответственно, левый верхний и правый нижний угол окна.
Цвет фона окна c задает процедура textbackground ( c );, а цвет символов -- textcolor ( c );.
Процедура без параметров clrscr; очищает текущее окно цветом фона.
Для установки текстового курсора в позицию окна с координатами (x, y) определена процедура gotoxy (x,y);.
Программно определить текущее положение курсора позволяют 2 стандартные функции Wherex:char; и Wherey:char;, возвращающие, соответственно, текущие x- и y-координату курсора.
Процедура ClrEol; удаляет все символы от позиции курсора до конца строки включительно, заполняя этот участок цветом фона.
Процедура Delline; полностью удаляет строку, в которой находится курсор, а Insline; вставляет пустую строку на экране в месте расположения курсора и заполняет ее цветом фона. Обе процедуры обеспечивают прокрутку содержимого окна.
Процедура Sound (F:word); включает встроенный динамик с частотой F герц, обеспечивая выдачу звукового сигнала.
Процедура Delay (T:word); задает задержку выполнения программы, равную T миллисекунд (1000 мс = 1 сек.). Эта процедура используется для организации задержек выполнения программы, а также всегда вызывается после sound, чтобы определить время звучания динамика.
Процедура без параметров NoSound; выключает динамик. Обязательно используется после пары Sound и Delay.
Наконец, в модуле crt определены 2 стандартных функции для работы с кодами нажатых клавиш. Функция readkey:char; возвращает код символа, прочитанный из буфера клавиатуры. Функция keyPressed:boolean; возвращает значение true, если была нажата клавиша на клавиатуре (за исключением вспомогательных клавиш Alt, Shift, Ctrl и т. д.). Использование последней функции позволяет организовать циклы, выполняющиеся до нажатия какой-либо клавиши.
При запуске программы из оболочки Паскаля монитор находится обычно в текстовом режиме и устанавливать его не нужно. Тем не менее, существует стандартная процедура textMode (Mode:integer), устанавливающая текстовый режим с номером Mode.
Стандартный цветной текстовый режим 25*80 позиций имеет номер 3, цветной текстовый режим 25*40 позиций -- номер 1.
Модуль crt содержит также системные переменные, которые можно изменять в соответствии с указанным для них типом.
Переменная CheckBreak:boolean; управляет реакций программы на прерывание по сочетанию клавиш Ctrl+Break. По умолчанию переменная имеет значение true (реакция включена).
Если переменная DirectVideo:boolean; имеет значение true, процедуры вывода на экран пишут данные непосредственно в видеопамять, не используя операционную систему. Это ускоряет вывод, но может использоваться только на полностью IBM-совместимых ЭВМ.
Переменная textAttr:integer; содержит текущий атрибут текста, сформированный по описанным выше правилам.
Приведем пример программы, определяющей коды нажатых клавиш. Конструкция repeat ... until в этой программе является образцом обработки ввода с клавиатуры. Проблема состоит в том, что функция readkey возвращает однобайтовый код клавиши, а ряд клавиш и сочетаний клавиш имеют двухбайтовые коды. С этим связан второй вызов функции readkey в программе.
uses crt;
var ch : char; {Символ, который вводим}
begin
clrscr; {Очистили экран}
writeln ('Программа выводит коды клавиш;',
' Esc - выход.');
repeat
writeln('Нажмите клавишу:');
ch := readkey; {Ждем ввода символа}
if ch = #0 then {Если нажата спец.
клавиша, то функция вернула 0,}
begin
ch := readkey; {и нужно прочитать код
символа дополнительно}
writeln('Нажата специальная клавиша ',
'с кодом ', ord(ch));
end
else {Иначе если нажата обычная клавиша -
сразу видим ее код}
writeln('Нажата клавиша с ASCII-кодом',
' ',ord(ch));
until ch=#27; {Значение 27 -
это код клавиши Escape}
writeln ('До свидания.');
end.
Как правило, в реальных программах широко используются небуквенные клавиши, такие как Enter, F1, Esc и т. д. Узнать их коды можно из таблиц ASCII-символов. Например, код клавиши Escape равен #27. Для записи клавиатурного кода на Паскале перед его значением ставится символ #, как сделано в этом примере. Более подробно об обработке нажатий клавиш рассказано в Приложении 5. Листинги 5-8 из Приложения 4 также иллюстрирует основные аспекты обработки нажатий клавиш.
В качестве развернутого примера использования функций модуля crt напишем программу, которая заполняет экран случайными цветными окнами, а также является примером проигрывания несложной "музыки" через встроенный динамик компьютера. Для рисования рамок в этой программе используются символы псевдографики, которые есть только в кодировке DOS (см. Приложение 1).
Program crt_example;
uses crt;
const minLen=10; {минимальная длина окна}
pause=500; {задержка при выводе звука}
blink=128; {установка бита мерцания}
var x1,y1,x2,y2 :integer;
{координаты окна}
background, {цвет фона окна}
color, {цвет текста}
freq, {частота звука}
setblink :integer; {есть/нет мерцание}
procedure doubleFrame (x1,y1,x2,y2:integer;
Header: string);
{Процедура рисует двойной рамкой окно
с заголовком и подготавливает его
внутреннюю часть для ввода текста}
{ x1,y1,x2,y2 - координаты окна}
{ header - заголовок окна}
var i,j: integer;
begin
Window (1,1,80,25);
{Рисуем верхнюю строку рамки }
gotoxy (x1,y1); write ('╔');
for i:=x1+1 to x2-1 do write('═');
write ('╗');
{Перебираем строки внутри окна}
for i:=y1+1 to y2-1 do begin
gotoxy (x1,i); write('║');
for j:=x1+1 to x2-1 do write (' ');
{Внутренность окна - пробелы}
write('║'); {Правая граница}
end;
{Аналогично рисуем нижнюю строку}
gotoxy (x1,y2); write('╚');
for i:=x1+1 to x2-1 do write('═');
write('╝');
gotoxy (x1+(x2-x1+1-Length(Header))
div 2,y1);
{Ставим курсор в середину верхней строки}
write (Header); {Выводим заголовок}
Window (x1+1,y1+1,x2-1,y2-1);
{Устанавливаем текущее окно внутри рамки}
gotoxy (1,1);{Ставим курсор в левый
верхний угол нового окна}
end;
begin
textbackground (BLACK);
Window (1,1,80,25);
{окно вывода - весь экран}
clrscr;
{Инициализируем генератор случайных чисел}
randomize;
DirectVideo:=true;
while not keyPressed do begin
{Пока не нажата клавиша,
выполняется цикл}
x1:= 1 + random(80-minLen);
x2:=x1 + minLen + random (80-x1-minLen);
y1:= 1 + random(25);
y2:= 1 + y1 + random (25-y1);
{Выбрали случайные координаты окна }
background:=random(8);
color:=random(16);
{Выбрали цвет фона и текста}
setblink:=random(2);
{Выбрали установку мерцания ДА или НЕТ}
textbackground (background);
textcolor(color+blink*setblink);
{Цвет текста с учетом мерцания}
doubleFrame (x1,y1,x2,y2,' Hello! ');
{Рисуем окно с помощью процедуры}
background := (textAttr and 112) shr 4;
{ Из байта цвета, содержащегося в
переменной textAttr, выделяем цвет
фона. Операция shr xx сдвигает
байт вправо на xx бит, а 112 в
двоичной системе это 01110000
(включены биты, отвечающие за фон) }
case background of
{ В зависимости от цвета фона выбираем
частоту звучания динамика }
0: freq:=262; {Частота ноты До}
1: freq:=294; { -"- Ре}
2: freq:=330; { -"- Ми}
3: freq:=349; { -"- Фа}
4: freq:=392; { -"- Соль}
5: freq:=440; { -"- Ля}
6: freq:=494; { -"- Си}
7: freq:=524; { -"- До}
end;
sound (freq); {Включаем динамик}
Delay (pause);
{Ждем, пока не истечет задержка}
Nosound; {Выключаем динамик!}
end; {Конец основного цикла}
{Восстанавливаем атрибуты текста и окно}
textbackground (BLACK);
textcolor (LIGHTGRAY);
Window (1,1,80,25);
clrscr;
end.
Использование этой программы на современном быстром процессоре может и не дать вам насладиться "космической музыкой" -- проблема в реализации функции Delay, учитывающей не реально прошедшее время в миллисекундах, а "условное" время, связанное с тактовой частотой процессора. Для исправления ситуации следует написать и применять собственную реализацию Delay, привязанную к функции GetTime модуля dos, позволяющей получить "абсолютное" системное время в часах, минутах, секундах и сотых долях секунды. Ниже приводится одна из возможных версий такой функции с комментариями основных действий и тестом:
uses crt,dos;
function getlongintTime:longint;
{Вернет системное время как longint}
var Hour,minute,second,sec100: word;
var k,r:longint;
begin
GetTime (Hour, minute, second, sec100);
{Прямое вычисление по формуле
Hour*360000+minute*6000+second*100+sec100
не сработает из-за неявного
преобразования word в longint:}
k:=Hour; r:=k*360000;
k:=minute; Inc (r,k*6000);
k:=second; Inc(r,k*100);
Inc(r,sec100); getlongintTime:=r;
end;
procedure MyDelay (ms:word);
{Корректно работает с задержками
до 65 сек.!}
var endTime,curTime : longint;
cor:boolean; {признак коррекции времени
с учетом перехода через сутки}
begin
cor:=false;
endTime:=getlongintTime + ms div 10;
if endTime>8639994 then cor:=true;
{Учитываем возможный переход через сутки;
23*360000+59*6000+59*100+99=8639999 и
отняли 5 мс с учетом частоты срабатывания
системного таймера BIOS}
repeat
curTime:=getlongintTime;
if cor=true then begin
if curTime<360000 then
Inc (curTime,8639994);
end;
until curTime>endTime;
end;
var Hour,minute,second,sec100: word;
begin
clrscr;
{setTime (23,59,58,99);}
{если раскомментарить - может изменить
системное время!}
repeat
gotoxy (1,1);
GetTime (Hour, minute, second, sec100);
write (Hour:2, ':', minute:2, ':',
second:2, ':',sec100:2, ' ');
MyDelay (500);
until keypressed;
end.
В Приложении 4 приведены также листинги программ для вывода кодов часто используемых клавиш, движения по экрану "прицела" с помощью клавиш со стрелками, а также программа создания несложного двухуровневого меню пользователя (листинги 5-7).
гостевая; E-mail |