Lekcja 6 - Obsługa klawiszy rozszerzonych i własne Menu
Źródła programów zamieszczonych w tej lekcji

Poznasz teraz jak obsługiwać klawisze rozszerzone (czyli klawisze kursora, klawisze funkcyjne, Insert, End itd.) oraz stworzysz swoje własne menu w trybie tekstowym.


Funkcja ReadKey

Składnia: znak:=ReadKey;

Jest to funkcja, która znajduje się w bibliotece CRT i zwraca znak odczytany z klawiatury ( nie cały ciąg znaków STRING a tylko jeden typu CHAR ). np.

USES CRT;

Var
  znak:char;

Begin
  WriteLn( 'Wcisnij jakis klawisz...');
  znak:=ReadKey;
  WriteLn( 'Wcisniety zostal klawisz: ',znak );
End.
Program czeka na wciśnięcie jakiegokolwiek klawisza i wyświetla go ( oczywiście nie mowię tu o klawiszach SHIFT, ALT czy CRTL bo one działają tylko w połączeniu z innymi znakami :)

Funkcja Chr

Składnia:
znak:=Chr(liczba);
znak:=#liczba;


Każdy litera, cyfra czy inny znak (np. ramki) posiadają swój własny numer (dokładniej jest to liczba od 0 do 255) i jest odczytywany z tablicy kodów ASCII, np. znakowi 'A' odpowiada liczba 65, znakowi 'a' liczba 97, a znakowi '2' liczba 50. Aby można było zamieniać liczbę na znak używa się właśnie funkcji Chr, która zwraca znak typu CHAR np.

Begin
 WriteLn(chr(70));
 WriteLn(chr(43));
 WriteLn(#43);
 WriteLn(chr(39));
End.
Program wyświetli w kolejnych liniach znaki: 'F', '+', jeszcze jeden '+' ( zamiast chr() mozesz używać znaczka # wynik jest ten sam ) i w ostatniej linii pojawi się niedający się zwyczajnie wyświetlić znaku apostrofu. A wiesz może dlaczego nie można go zwyczajnie wyświetlić ? Odpowiedź jest prosta: jeżeli wstawimy go np. w procedurze WriteLn to procedura uzna go za znak zaczynający lub kończący zmienną typu string, nie da się więc tak zrobić:
WriteLn( 'Alfabet Morse'a' );
Pascal widzi tylko zmienną 'Alfabet Morse' i nie wie co dalej zrobić z resztą ( a' ) a ponieważ zmienne String można łączyć ze zmiennymi Char, tak więc poprawna linijka wyglądała by tak:
WriteLn( 'Alfabet Morse'+chr(39)+'a' );
lub tak:
WriteLn( 'Alfabet Morse'+#39+'a' );
ewelntualnie tak:
WriteLn( 'Alfabet Morse',#39,'a' );
Niektóre kody są znakami sterującymi np. chr(13) odpowiada klawiszowi ENTER, chr(27) klawiszowi ESC, chr(8) klawiszowi BACKSPACE, a chr(7) odpowiada pipnięciu przez głośniczek komputera, spróbuj coś takiego:
Begin
  WriteLn(chr(7));
End.
lub ten poniżej który czeka na wciśnięcie klawisza ESC ( na żaden inny nie reaguje ):
USES CRT;

Var
  znak:char;

Begin
  ClrScr;
  WriteLn('Wcisnij klawisz ESC');
  Repeat
    znak:=ReadKey;
  Until znak=Chr(27);
End.
Jeżeli chcesz to możesz teraz sobie ściągnąć
Rezydentną Tablicę ASCII dla DOS'a dzięki niej będziesz wiedział, jakie kody posiadają poszczególne znaki.

Funkcja Ord

Składnia: liczba:=Ord(znak);

Ta funkcja jest podobna do funkcji Chr, tylko że w niej zamieniane jest na odwrót, nie liczby na znaki, tylko znaki na liczby :) np. ord('A')=65 ord('a')=97 ord('2')=50 itd. np.

USES CRT;

Var
  znak:char;

Begin
  Repeat
    znak:=ReadKey;
    WriteLn(znak,'   ',ord(znak));
  Until znak=Chr(27);
End.
Program ten czeka na wciśnięcie znaku i wyświetla go, podając jednocześnie jego kod ASCII. Działa tak długo póki nie wciśniemy klawisza ESC.

Obsługa Klawiszy Rozszerzonych

Klawisze rozszerzone podobnie jak zwykłe odczytuje się funkcją ReadKey. Jest jednak jedna różnica, jeżeli to jest klawisz rozszerzony to funkcja ReadKey zwróci nam wartość chr(0), aby rozpoznać który to klawisz z rozszerzonych, to należy POWTÓRNIE ODCZYTAĆ KLAWISZ funkcją ReadKey. Aby to objaśnić obejrzyj przykład:

USES CRT;

Var
  normalny,rozszerzony:char;

Begin
  WriteLn( 'Wcisnij jakis klawisz...');
  normalny:=ReadKey;
  if normalny=chr(0) then
    Begin
      rozszerzony:=ReadKey;
      WriteLn( 'Wcisniety zostal rozszerzony klawisz: ',rozszerzony );
    End Else WriteLn( 'Wcisniety zostal klawisz: ',normalny );
End.
Program czeka na wciśnięcie klawisza, jeżeli jest to rozszerzony ( czyli przeczytany=chr(0) ) powtórnie go czyta i wyświetla wartość ROZSZERZONY, jeżeli nie to omija powtórne czytanie i wyświetla wartość NORMALNY. Tak więc jeżeli wciśniemy klawisz "kursor w prawo" to otrzymamy wartość "rozszerzony M" itd. zróbmy więc teraz podstawę do obsługi kursorów:
USES CRT;

Var
  c1,c2:char;

Begin
  Repeat
  c1:=ReadKey;
  c2:=' ';                                              {1}
  if c1=chr(0) then c2:=ReadKey;                        {2}
  if c2='H' then WriteLn('Kursor w górę');
  if c2='P' then WriteLn('Kursor w dół');
  if c2='M' then WriteLn('Kursor w prawo');
  if c2='K' then WriteLn('Kursor w lewo');
  Until c1=chr(27);
End.
Program reaguje tylko na klawisze kursora i ESC. W linii {1} musiałem jakoś wyzerować zmienną "C2" a to dlatego że jeżeli wcisnęlibyśmy klawisz np. "kursor w lewo" a potem jakiś zwykły np. spację to program by wyświetlił ponownie "kursor w lewo" gdyż w linii {2} nie odczytałby powtórnie klawisza { c1 byłoby wtedy różne od chr(0) } i pozostałaby w zmiennej C2 poprzednia wartość.

Procedura Inc

Składnia: Inc(zmienna);

Normalnie to jest procedura zwiększająca wartość zmiennej o "1" czyli np. "X:=X+1" to jest to samo co "Inc(X)". Ale ta procedura zwiększa również inne typy np. typ CHAR jeżeli zmienna C= 'a' to po wykonaniu "Inc(C);" zmienna C będzie miała wartość o "1" większą czyli: 'b'.


Procedura Dec

Składnia: Dec(zmienna);

Jest to procedura podobna do Inc z tą tylko różnicą że ta nie zwiększa o "1" tylko ZMNIEJSZA o "1"


Menu w trybie tekstowym sterowane kursorami

Na początek zrobimy menu z trzema opcjami wyboru, używając tu tablice bo bez nich byłoby ciężko, będzie to trochę większy program od tych co robiliśmy do tej pory ale mam nadzieję że sobie poradzisz :)

USES CRT;
Var
 c1,c2:char;
 y:byte;
 tablica:array[1..3]of string;

Procedure info;                                {1}
Begin
End;

Procedure glowny_program;                      {2}
Begin
End;

Begin
  Tablica[1]:='   Info    ';                   {3}
  Tablica[2]:='  Program  ';                   {4}
  Tablica[3]:='  Wyjscie  ';                   {5}
  ClrScr;
  TextColor(15);
  For y:=1 to 3 do                             {6}
    Begin                                      {7}
      TextColor(15);                           {8}
      TextBackGround(0);                       {9}
      GotoXY(32,11+y);                         {10}
      Write(tablica[y]);                       {11}
    End;                                       {12}
  y:=1;                                        {13}
  Repeat                                       {14}
    TextColor(0);                              {15}
    TextBackGround(15);                        {16}
    GotoXY(32,11+y);                           {17}
    Write(tablica[y]);                         {18}
    c1:=ReadKey;                               {19}
    c2:=' ';                                   {20}
    If c1=Chr(0) Then c2:=ReadKey;             {21}
    TextColor(15);                             {22}
    TextBackGround(0);                         {23}
    GotoXY(32,11+y);                           {24}
    Write(tablica[y]);                         {25}
    If c2='H' Then Dec(y);                     {26}
    If c2='P' Then Inc(y);                     {27}
    If y=0 Then y:=3;                          {28}
    If y=4 Then y:=1;                          {29}
    If c1=Chr(27) Then y:=3;                   {30}
  Until (c1=chr(27)) or (c1=chr(13));          {31}
  If y=1 Then info;                            {32}
  If y=2 Then glowny_program;                  {33}
End.
Teraz wyjaśnienie:
{1, 2} - przykładowe procedury które będą uruchamiane po wybraniu ich z menu
{3 - 5} - wprowadzenie do zmiennych wartości kolejnych pól menu
{6 - 12} - wyświetlenie kolejnych pozycji menu
{13} - wprowadzenie do zmiennej Y wartości "1" będzie to nasza zmienna informująca na której aktualnie pozycji menu znajdujemy się
{14 - 31} początek pętli kończącej się dopiero po wciśnięciu klawisza ENTER lub ESC
{15, 16} zmiana kolorów tła i tekstu na przeciwny (tło białe, tekst czarny)
{17, 18} wyświetlenie Y pozycji menu w nowych kolorach
{19} czekanie na wciśnięcie klawisza
{20} wyczyszczenie zmiennej C2
{21} odczytanie znaku jeżeli jest to klawisz rozszerzony
{22, 23} przywrócenie normalnych kolorów ( tło czarne, tekst biały )
{24, 25} wyświetlenie Y pozycji menu w zwykłych kolorach ( zrobiliśmy to dlatego że jeżeli zmieni się pozycja w menu aby poprzednia już nam się nie "świeciła"
{26} jeżeli klawisz to "kursor górę" zmniejsz zawartość zmiennej Y o "1"
{27} jeżeli klawisz to "kursor dół" zwiększ zawartość zmiennej Y o "1"
{28} jeżeli Y=0 ( czyli poprzednio menu było na 1 pozycji i pojechaliśmy w górę ) podstaw do Y wartość "3" (dzięki temu aktualną pozycją stanie się 3 i będzie nam się tak cały czas "kręcić w kółko" )
{29} jeżeli Y=4 ( czyli poprzednio menu było na 3 pozycji i pojechaliśmy w dół ) podstaw do Y wartość "1" ( tak więc powracamy do "1" pozycji )
{30} jeżeli wciśnięty klawisz to ESC podstaw do zmiennej Y=3 ( czyli pozycję "wyjście", zwróć uwagę że gdybyś tego nie zrobił, a akurat znajdowałbyś się na pozycji np. "Info" to po wciśnięciu ESC i tak uruchomiła by się procedura Info ! )
{31} jeżeli wciśnięty klawisz to ENTER lub ESC opuść pętlę
{32 - 33} uruchom odpowiednie procedury w zależności od wartości zmiennej Y

Ot i cała filozofia Menu ( trochę gorzej jest jeżeli pozycji jest więcej niż wierszy na ekranie ale nie będę teraz bardziej tym męczył :) Chcę abyś teraz przypatrzył się liniom {8 - 11}, {15 - 18} i {22 - 25}. Linie te są prawie identyczne tak więc aż kusi aby zrobić z nich procedurkę :) A oto program z tą właśnie dodatkową procedurką:
USES CRT;
Var
 c1,c2:char;
 y:byte;
 tablica:array[1..3]of string;

Procedure info;
Begin
End;

Procedure glowny_program;
Begin
End;

Procedure wyswietl(ktory,kolor,tlo:byte);      {1}
Begin
  TextColor(kolor);                            {2}
  TextBackGround(tlo);                         {3}
  GotoXY(32,11+ktory);                         {4}
  Write(tablica[ktory]);                       {5}
End;

Begin
  Tablica[1]:='   Info    ';
  Tablica[2]:='  Program  ';
  Tablica[3]:='  Wyjscie  ';
  ClrScr;
  For y:=1 To 3 Do wyswietl(y,15,0);           {6}
  y:=1;
  Repeat
    wyswietl(y,0,15);                          {7}
    c1:=ReadKey;
    c2:=' ';
    If c1=chr(0) Then c2:=ReadKey;
    wyswietl(y,15,0);                          {8}
    If c2='H' Then Dec(y);
    If c2='P' Then Inc(y);
    If y=0 Then y:=3;
    If y=4 Then y:=1;
    If c1=chr(27) Then y:=3;
  Until (c1=chr(27)) or (c1=chr(13));
  If y=1 Then info;
  If y=2 Then glowny_program;
End.
{1} nowa procedura, jej parametrami są: "KTORY" będący zmienną informującą którą pozycję wyświetlić, "KOLOR" - kolor tekstu i "TLO" kolor tła
{2, 3} zmieniają kolor tekstu i tła
{4, 5} wyświetlenie pozycji "KTORY" w kolorach "KOLOR" i "TLO"

I na tym zakończymy tą lekcję ( spróbuj teraz sam zmodyfikować tak program aby było w nim do wyboru 5 pozycji np. "Info", "Tabliczka Mnożenia", "Dom", "Drzewo", "Wyjście" i wypełnij te procedury aby wykonywały to co powinny czyli: Wyświetlały informacje o autorze, wyświetlały tabliczkę mnożenia oraz rysowały dom i drzewo ( w trybie graficznym ). To takie małe zadanko domowe do poćwiczenia :)

Główną część ostatniego programu można jeszcze bardziej uprościć procedurami, tylko że będzie ich coraz więcej i więcej więc przydałoby się gdzieś je umieścić i właśnie to będzie tematem kolejnej lekcji: własne biblioteki. Biorąc pod uwagę że w niektórych programach używamy dokładnie tych samych procedur umieścimy je w jednym miejscu aby mieć do nich swobodny dostęp.

Powrot na Strone Glowna