Модуль Crt містить процедури й функції, призначені для роботи з екраном у текстовому режимі. Як і ряд інших стандартних модулів, crt вбудований у компілятор і втримується у файлі Turbo.tpl.
Екран у текстовому режимі розбивається на окремі рядки, а кожний рядок - на позиції, причому в кожну позицію може бути поміщений тільки 1 символ з набору ASCII.
Для повного опису екранної позиції слід задати ще й атрибут, що містить інформацію про колір символу й тла на екрані. Символ і атрибут займають у пам'яті по 1 байту. Структура байта-атрибута показана нижче:
Біти
7 6 5 4 3 2 1 0
┌─┬─┬─┬─┬─┬─┬─┬─┐
│М│Ф│Ф│Ф│Ц│Ц│Ц│Ц│
└─┴─┴─┴─┴─┴─┴─┴─┘
Біт 7 управляє мерехтінням символу (символ на екрані мерехтить, якщо він установлений в 1), біти 4-6 містять колір тла ( від 0 до 7 включно), а біти 0-3 - колір символу ( від 0 до 15). Зрозуміло, програмістові звичайно не доводиться заповнювати байт атрибута по битках, для цього є стандартні коди квітів. Основні кольори кодуються цифрами від 0 до 15, причому колір тексту може бути будь-яким, а колір тла - тільки з перших 7 квітів. Перелічимо головні кольори:
0 - чорний (BLACK) 8 - темно-сірий (DARKGRAY)
1 - синій (BLUE) 9 - блакитний (LIGHTBLUE)
2 - зелений (GREEN) 14 - жовтий (YELLOW)
4 - червоний (RED) 15 - білий (WHITE)
7 - ясно-сірий (LIGHTGRAY)
Можна звертатися до кольору як по цифровому коду, так і по англомовному імені.
Звичайно використовувані текстові режими мають 25 рядків і 80 позицій у рядку. Нумерація рядків і позицій починається з 1 і вважається ліворуч праворуч і зверху вниз. Увесь екран у текстовому режимі може бути описаний парою координат (1,1),(80,25). Зверніть увагу на порядок запису - СТОВПЕЦЬ, потім РЯДОК.
Нижче коротко розглянуті основні процедури й функції модуля. Для функцій в описі зазначене ключове слово function.
Позначення:
X,X1,X2 - координати стовпців екрана,
Y,Y1,Y2 - координати рядків екрана,
C - значення кольору.
Особливість модуля Crt у тому, що він дозволяє працювати не тільки з усім екраном, але й з виділеним на ньому прямокутним вікном. При цьому все введення, вивід і 'прокручування' тексту відбуваються в межах вікна. За замовчуванням розміри вікна збігаються з розмірами екрана, але можна явно встановити їхнім звертанням до процедури
Window (X1,Y1,X2,Y2);
де (X1,Y1) і (X2,Y2), відповідно, лівий верхній і правий нижній кут вікна.
Textbackground (Color); - Задає колір тла Color
Textcolor (Color); - Задає колір символів Color
Clrscr; - Очищає поточне вікно кольором тла.
Gotoxy (X,Y); - Установлює курсор у позицію ВІКНА з координатами (X,Y).
Clreol; - Видаляє всі символи від курсору включно до кінця рядка, заповнюючи цю ділянку кольором тла.
Delline; - Видаляє рядок, у якому перебуває курсор.
Insline; - Вставляє порожній рядок на екрані в місці розташування курсору й заповнює її кольором тла.
function Wherex:Char; function Wherey:Char; - Функції повертають, відповідно, що течуть X- і Y-Координати курсору.
Sound (Freq); - включає динамік із частотою Freq герц.
Delay (Time); - Задає затримку виконання програми Time миллисекунд (1000мс = 1 секунді). Використовується, зокрема, після Sound, щоб визначити час звучання динаміка.
Nosound; - Виключає динамік. Обов'язково використовується після пари Sound і Delay.
function Readkey:Char; - Повертає код символу, прочитаний з буфера клавіатури.
function Keypressed: Boolean; - Повертає TRUE, якщо була натиснута клавіша на клавіатурі ( за винятком допоміжних клавіш Alt, Shift, Ctrl і т.д.).
При запуску програми з оболонки Паскаля монітор перебуває звичайно в текстовому режимі й установлювати його не потрібно. Проте, існує процедура Textmode(Mode:Integer), що встановлює текстовий режим з номером Mode.
Стандартний кольоровий текстовий режим 25*80 позицій має номер 3, кольоровий текстовий режим 25*40 позицій - номер 1.
Модуль Crt містить також змінні, які можна змінювати відповідно до зазначеного для них типом:
Checkbreak:Boolean; - Якщо TRUE ( за замовчуванням), програма реагує на переривання по комбінації клавіш Ctrl+Break.
Directvideo:Boolean; - Якщо TRUE, процедури Write пишуть безпосередньо у відеопам'ять, не використовуючи операційну систему. Це прискорює вивід, але може використовуватися тільки на повністю 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 також ілюструє основні аспекти обробки натискань клавіш.
Пр. Ця програма заповнює екран випадковими кольоровими вікнами, а також являє приклад програвання нескладної "музики" через вбудований динамік комп'ютера.
Program Crt_Example; {Приклад використання модуля Crt}
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; { Дозволяємо писати прямо у відеопам'ять - }
{ тільки для повністю Ibm-Сумісних машин!}
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); {Вибираємо колір тла з 8 можливих}
Color:=Random(16); {Вибираємо колір тексту з 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
Gettime (Hour, Minute, Second, Sec100);
Write (Hour:2,':',Minute:2,':',Second:2,':',Sec100:2,' ');
Mydelay (500);
Gettime (Hour, Minute, Second, Sec100);
Writeln (Hour:2,':',Minute:2,':',Second:2,':',Sec100:2,' ');
until keypressed;
end.
У Додатку 4 наведені також лістинги програм для виведення кодів часто використовуваних клавіш, руху по екрану "прицілу" за допомогою клавіш зі стрілками, а також програма створення нескладного дворівневого меню користувача (лістинги 5-7).