Podstawy Programowania Wykład dwunasty: Modu ł crt i komunikacja z użytkownikiem
1.Obsługa klawiatur i ekranu w trybie tekstowym Do interaktywnej pracy z komputerem służy jego użytkownikowi klawiatura i monitor. Współczesne karty graficzne pozwalaj ą wyświetla ć informacje w dwóch rodzajach trybów wyświetlania: graficznych, gdzie obraz jest złożony z dużej ilości niewielkich punktów zwanych pikselami, oraz w tekstowych, gdzie obraz jest podzielony na miejsca, które zajmuje dokładnie jeden znak. Moduł crt zwiera procedur i funkcje, wraz z innymi elementami, które pozwalaj ą na zarządzanie zawartości ą ekranu w trybach tekstowych. Ponadto cz ęść z nich związana jest z obsług ą klawiatury i głośnika, jaki zosta ł wbudowany w komputery PC (PC Speaker). 2.Tryby tekstowe Do zmiany trybu tekstowego służy procedura textmode. Przyjmuje ona jeden parametr wywołania, który jest wartości ą, wyrażeniem lub zmienn ą typu integer. Najczęściej parametrem tym jest jedna z predefiniowanych w module crt stałych, określających rodzaj trybu. Jeśli procedura textmode zostanie wywołana ze sta łą BW40, to ekran zostanie przełączony w czarno-biały tryb tekstowy, o wymiarach: 40 kolumn i 25 wierszy (można na nim równocześnie wyświetli ć maksymalnie 1000 znaków) 1. W przypadku wywołania opisywanej procedury ze sta łą CO40 wymiary pozostaj ą bez zmian, ale można używa ć 16 kolorów. Przełączenie do trybów, w których ekran ma 80 kolumn i 25 wierszy uzyskuje si ę za pomoc ą stałych BW80 i CO80. W przypadku pierwszej stałej jest to tryb czarno-biały, a w przypadku drugiej kolorowy. Tryb o maksymalnej rozdzielczości 2, 80 kolumn i 50 wierszy dla kart graficznych zgodnych ze standardem EGA, możemy włączy ć za pomoc ą stałej Font8x8. Istniej ą jeszcze trzy stałe, które mog ą by ć parametrami wywołania textmode: Mono która włącza specyficzny tryb tekstowy nieużywanej ju ż dzi ś karty oraz C40 i C80, które s ą tożsame ze stałymi CO40 i CO80. Oczywiście stałe te posiadają odpowiednie wartości: BW40 = 0, CO40=1, BW80=2, CO80=3, Mono=7, Font8x8=256, C40=CO40, C80=CO80. W module crt zadeklarowana jest również zmienna typu word o nazwie LastMode, która zapamiętuje numer trybu przed jego zmian ą. Aby przywróci ć poprzedni tryb wyświetlania znaków wystarczy więc wywoła ć textmode ze zamienn ą LastMode, jako parametrem wywołania. 1 Tak, jak i inne identyfikatory w Pascalu, nazwy tych stałych mog ą by ć pisane zarówno dużymi, jak i małymi literami. 2 W tym kontekście słowo to oznacza liczb ę wyświetlanych równocześnie znaków na ekranie. 2
3.Kolory w trybach tekstowych W kolorowych trybach tekstowych można używa ć maksymalnie 16 kolorów. Możliwe jest określenie zarówno koloru znaku, za pomoc ą procedury textcolor, jak i koloru tła, na którym znak jest wyświetlany. To ostatnie realizujemy przy pomocy procedury textbackground. Obie procedury przyjmuj ą jako parametr wywołania zmienn ą, wyrażenie lub warto ść typu byte, ale akceptowalne są w przypadku textcolor tylko wartości od 0 do 15, a w przypadku textbackgroud tylko wartości od 0 do 7. Możemy je podawa ć bezpośrednio lub uży ć stałych określających kolor, które równie ż zostały zdefiniowane w module crt. Jest ich piętnaście: Black=0 określa kolor czarny, Green=2 określa kolor zielony, Blue=1, określa kolor niebieski, Cyan=3 określa kolor turkusowy, kolor czerwony, Magenta=5 określa kolor karmazynowy, kolor brązowy, LightGray=7, określa kolor jasnoszary, kolor ciemnoszary, LightBlue=9 określa kolor jasnoniebieski, określa kolor jasnozielony, LightRed=12 określa kolor jasnoczerwony, Red=4, określa Brown=6, określa DarkGray=8 określa LightGreen=10 LightCyan=11 określa kolor jasno turkusowy, LightMagenta=13 określa kolor jasno ś ł karmazynowy, Yellow=14 określa kolor żółty, White=15, okre la kolor bia y. Istnieje jeszcze stała Blink=128. Dodanie jej do stałej określającej kolor powoduje, że znak o tym kolorze będzie miga ł na ekranie. Jeśli chcemy zmniejszy ć lub zwiększy ć jasno ść znaków na ekranie możemy użyć odpowiednio procedury LowVideo lub HighVideo. Obie te procedury są bezparametrowe. Aby przywróci ć stare ustawienia jasności znaków możemy uży ć równie ż bezparametrowej procedury NormVideo. W module crt jest również zadeklarowana zmienna typu byte o nazwie TextAttr, która pozwala na bezpośrednie określenie atrybutów (koloru, koloru tła, migania) znaku, przy czym najstarszy bit tej zmiennej odpowiada za migotanie (0 nie miga, 1 miga), trzy następne za kolor tła, a cztery ostatnie za kolor znaku. 4. Wiersze W module crt istniej ą procedur pozwalające manipulowa ć wierszami znaków, które s ą wyświetlane na ekranie. Wszystkie te procedury nie wymagaj ą żadnych parametrów wywołania. Procedura clreol usuwa z ekranu wszystkie znaki począwszy od bieżącej pozycji kursora, a ż do końca wiersza. Procedura insline wstawia wiersz wypełniony pustymi znakami za wierszem w którym jest kursor. Procedura delline usuwa znaki z wiersza ekranu w którym jest kursor. 3
5. Okna Modu ł crt, umożliwia określenie na ekranie okien 3, w obrębie których będą wyświetlane znaki, jak równie ż pozwala na określanie pozycji kursora w obrębie tych okien. Do utworzenia na ekranie okna służy procedura window. Pobiera ona cztery parametry wywołania. Pierwsza para tych parametrów określa odpowiednio współrzędn ą poziom ą i pionow ą lewego górnego rogu okna, natomiast następna para określa odpowiednio współrzędn ą poziom ą i pionową prawego dolnego rogu okna. Parametry te mog ą by ć wartościami, wyrażeniami lub zmiennymi typu byte. Ich wartości nie powinny jednak przekraczać maksymalnych wartości kolumny i wiersza, określonych dla danego trybu tekstowego (współrzędna pozioma odpowiada za kolumny, pionowa za wiersze). Współrzędne lewego górnego rogu bieżącego okna s ą przechowywane w zmiennej WindMin typu word, a współrzędne prawego dolnego rogu są przechowywane w zmiennej WindMax, te ż typu word. Starszy bajt tych zmiennych zawiera warto ść współrzędnej poziomej, młodszy współrzędnej pionowej. Położenie kursora na ekranie możemy zmieni ć za pomoc ą procedury gotoxy, która pobiera dwa parametry wywołania. Oba mog ą by ć wartościami, zmiennymi lub wyrażeniami typu byte, ale podobnie, jak ma to miejsce w przypadku procedury window ich wartości nie powinny przekraczać maksymalnego numeru wiersza i kolumny dla danego trybu tekstowego. Pierwszy parametr określa współrzędn ą poziom ą miejsca, w którym chcemy umieści ć kursor (kolumn ę), druga określa współrzędn ą poziom ą tego miejsca (wiersz). Współrzędne te s ą liczone zawsze względem bieżącego okna, czyli jeśli wywołanie tej procedury ma posta ć gotoxy(1,1), to położenie kursora będzie się zależało od tego, czy wywołaliśmy wcześniej procedur ę window i z jakimi parametrami. Bieżące położenie kursora na ekranie możemy określi ć za pomoc ą funkcji wherex i wherey. Nie pobieraj ą one żadnych parametrów wywołania, ale zwracaj ą wartości typu byte, które określaj ą odpowiednio składow ą poziom ą i pionow ą bieżącego położenia kursora. Położenie to jest oczywiście liczone względem lewego górnego rogu bieżącego okna. 6. Obsługa klawiatury W module crt zdefiniowane s ą dwie funkcje, które pozwalaj ą na obsługę klawiatury. Zanim przejdziemy do ich omówienia musimy dowiedzie ć si ę, że w pamięci komputera wyróżniony jest niewielki fragment, zwany buforem klawiatury. Do tego fragmentu pamięci trafiaj ą między innymi kody ASCII znaków związanych z naciśniętymi klawiszami. Opisywane funkcje działają 3 Po przez termin okno rozumiemy w tym kontekście wydzielony obszar ekranu, a nie obiekt znany między innymi z systemów operacyjnych Windows firmy Microsoft. 4
więc na zwartości tego bufora, a nie bezpośrednio na klawiaturze. Funkcja KeyPressed nie pobiera żadnych parametrów wywołania, a zwraca warto ść true jeśli w buforze klawiatury znajduje si ę znak do odczytania 4. Funkcja readkey równie ż jest bezparametrowa, ale zwraca warto ść typu char. Jest to znak odpowiadający klawiszowi, który zosta ł naciśnięty. Warto przy okazji omawiania tej funkcji napisa ć o pewnym problemie z ni ą związanym, który dosy ć często jest spotykany. Otó ż funkcji tej można uży ć do wstrzymania wykonywania programu do czasu naciśnięcia przez użytkownika dowolnego klawisza. Niestety nie zawsze ten sposób działa zgodnie z założeniami. Niektóre klawisze zwracaj ą do bufora dwa kody ASCII. Do tych klawiszy nale żą klawisze kursorów i klawisze funkcyjne (od F1 do F12). Rozważmy następujący program: uses crt; clrscr; writeln('pierwszy napis'); writeln('drugi napis'); writeln('trzeci napis'); end. Jeśli po ukazaniu si ę na ekranie pierwszego napisu naciśniemy dowolny z klawiszy kursorów, to na ekranie pojawi si ę drugi i trzeci napis, a program zatrzyma si ę dopiero na ostatnim readkey. Tajemnica tego zachowania jest taka, że opisywana funkcja, w wyniku swego wywołania zwraca tylko jeden znak, a klawisz kursora zapisuje do bufora klawiatury dwa znaku. Pierwsze wywołanie readkey odczyta pierwszy z nich, a drugie nie będzie czekało na naciśnięcie klawisza przez użytkownika, bo drugi znak ju ż będzie gotów do odczytania w buforze klawiatury. Rozwiązanie tego problemu polega na umieszczeniu przed każdym wywołaniem readkey krótkiej pętli, która czyściłaby bufor klawiatury: while keypressed do Pętl ę while możemy odczyta ć następująco: dopóki jest w buforze klawiatur jaki ś znak, to go odczytaj. Ta pętla gwarantuje nam, że następujące po niej 4 Według pomocy w środowisku Turbo Pascala, funkcja ta zwraca warto ść true jeśli został naciśnięty klawisz. Nie do końca odpowiada to prawdzie. 5
wywołanie readkey będzie musiało poczeka ć, a ż użytkownik naciśnie jakiś klawisz i zapisze tym samym przynajmniej jeden znak do bufora klawiatury. Innymi słowy przed wywołaniem readkey bufor klawiatury będzie oczyszczony. 7.Inne procedury z modułu crt Jeśli chcemy wstrzyma ć wykonanie pewnej grupy instrukcji programu na określon ą ilo ść czasu, to możemy posłuży ć si ę procedur ą delay. Jej wywołanie musimy umieści ć przed t ą grup ą instrukcji. Jako parametr wywołania ta procedura przyjmuje warto ść, zmienn ą lub wyrażenie typu word. Jeśli ta warto ść wynosi 1, to procedura wstrzyma wykonanie programu na jedną milisekund ę [ms]. Poniewa ż maksymaln ą wartości ą dla typu word jest 65535, to za pomoc ą jednokrotnego wywołania tej procedury możemy opóźni ć program na nieco dłużej ni ż jedn ą minut ę i pi ęć i pó ł sekundy. Do sterowania wbudowanym w komputer głośnikiem (PC Speaker) służy procedura sound. Jako parametr wywołania może przyj ąć zmienn ą, warto ść lub wyrażenie typu word. Określa ono częstotliwo ść dźwięku, jaki będzie emitowany przez głośnik. Teoretycznie możliwe jest osiągnięcie dźwięków leżących poza zakresem słyszalności czł owieka (od 20 Hz do 20 khz), ale ze względu na jako ść głośnika (a raczej jej brak) jest to mało prawdopodobne. Dźwięk wyłączamy wywołując procedur ę nosound 5. Jest to procedura bez parametrów. Opisane tu procedury kończ ą list ę procedur i funkcji modułu crt, z którymi si ę zapoznamy. Inne elementy tego modułu nie będ ą tu ju ż opisywane. 8.Przykłady program okna_w_trybie_tekstowym; uses crt; procedure okno(x1,y1,x2,y2:byte); var i:byte; window(x1,y1,x2,y2); gotoxy(1,1); 5 Pisząc programy wykorzystujące dźwięk najlepiej mie ć w odwodzie krótki program, składający si ę tylko z wywołania nosound. Uruchomienie go, kiedy zawiesi si ę pisany przez nas program, może zaoszczędzi ć irytacji osobom znajdującym si ę w naszym otoczeniu :-) 6
for i:=1 to 10 do writeln('napis w oknie'); delay(1000); gotoxy(5,2); clreol; delay(1000); gotoxy(1,3); delline; delay(1000); gotoxy(1,4); insline; delay(1000); procedure wyswietl(zx,zy:byte); var x,y:byte; x:=random(zx-20); y:=random(zy-20); okno(x,y,x+20,y+20); clrscr; randomize; textmode(font8x8); wyswietl(80,50); textmode(co80); wyswietl(80,25); textmode(co40); wyswietl(40,25); readln; end. 7
Pierwszy przykładowy program wyświetla w losowo umieszczonym na ekranie oknie dziesi ęć wierszy o treści Napis w oknie, po jednosekundowej przerwie usuwa cz ęść znaków z piątego wiersza, po kolejnej sekundzie usuwa trzeci wiersz i po upływie takiego samego odcinka czasu wstawia nowy wiersz w miejscu, gdzie by ł czwarty wiersz, a następnie czeka jedn ą sekund ę. Ta czynno ść jest powtarzana dla trzech trybów graficznych. Procedura okno wyświetla okno o współrzędnych przekazanych jej przez parametry, umieszcza kursor w lewym górnym rogu tego okna i wypisuje dziesi ęć wierszy o podanej wcześniej treści. Kolejne czynności wykonywane s ą z jednosekundowym opóźnieniem między wykonaniem każ dej z nich. Polegaj ą one na usunięciu części znaków z wiersza, usunięciu całego wiersza i wstawieniu nowego. Przed powrotem z procedury komputer równie ż czeka jedn ą sekund ę. Procedura wyswietl losuje współrzędne lewego górnego rogu okna, które s ą przekazywane do procedury okno. Utworzone okno ma wymiary 20x20. Wymiary okna są uwzględniane w parametrze wywołania funkcji random, tak aby wylosowane współrzędne nie spowodowały wyświetlenie całości lub części okna poza ekranem. W programie głównym procedura wyswietl jest wywoływana po każdym przełączeniu ekranu w inny tryb tekstowy, z odpowiednimi dla danego trybu parametrami wywołania, które określaj ą liczb ę wierszy i kolumn w danym trybie. program textdemo; uses crt; var a:word; procedure demo(x1,y1,x2,y2:byte; migaj:boolean); var i:byte; a:word; gotoxy(x1,y1); window(x1,y1,x2,y2); for i:=black to white do 8
if i=0 then textbackground(white) else textbackground(black); if migaj then textcolor(i+blink) else textcolor(i); write('tekst'); while keypressed do repeat until keypressed; gotoxy(1,1); for i:=black to lightgray do textbackground(i); write('tekst'); delay(500); sound(1000); delay(500); nosound; clrscr; textmode(co40); demo(20,5,24,21,false); while keypressed do textmode(co80); demo(40,5,44,21,false); while keypressed do textmode(co40); demo(20,5,24,21,true); while keypressed do textmode(co80); demo(40,5,44,21,true); 9
while keypressed do textmode(lastmode); normvideo; end. Procedura demo przyjmuje pi ęć parametrów. S ą to współrzędne okna oraz znacznik określający, czy wypisywany tekst ma miga ć ( true), czy nie. Pierwszą czynności ą jak ą wykonuje procedura jest umieszczenie kursora w punkcie o podanych współrzędnych i utworzenie okna o określonych wymiarach 6. W oknie tym wypisywany jest wyraz tekst w kolejnych wierszach, za każdym razem w innym kolorze 7. W zależności od parametru migaj do koloru dodawany jest atrybut migania lub nie. Po wykonaniu tej czynności program oczekuje na naciśnięcie przez użytkownika klawisza w pętli repeat until keypressed; co można odczyta ć jako nie rób nic tak długo a ż użytkownik naciśnie jakiś klawisz. Przed wykonaniem tej pętli wykonywana jest pętla while keypressed do aby oczyści ć bufor klawiatury. Po naciśnięciu przez użytkownika dowolnego klawisza kursor wraca do lewego górnego rogu okna i napis tekst jest ponownie w nim umieszczany, tym razem jednak zmienia si ę kolor jego tła. Po wykonaniu tej czynności program generuje dźwięk o częstotliwości 1 khz i trwający pó ł sekundy. W bloku programu głównego procedura demo jest wywoływana cztery razy, dwukrotnie dla trybu CO80 i dwukrotnie dla trybu CO40. Za drugim razem wyraz tekst po wypisaniu migocze. Między kolejnymi wywołaniami tej procedury wykonanie programy jest zatrzymywane przy pomocy funkcji readkey, do czasu naciśnięcia przez użytkownika dowolnego klawisza. Przed wywołaniem tej funkcji wykonywana jest pętla czyszcząca zawarto ść bufora klawiatury. Po wykonaniu opisanych czynności przywracany jest poprzedni tryb tekstowy i wywoływana jest procedura normvideo. program kursor; uses crt; procedure ruch; var a:char; repeat a:= if a = #0 then 6 Wynikających z przekazanych do procedury współrzędnych. 7 Pierwszy wyraz jest wypisywany czarnymi znakami, więc zosta ł umieszczony na białym tle. 10
a:= if a=#60 then clrscr; if a=#59 then write('x: ',wherex, ', y: ',wherey); if a=#72 then gotoxy(wherex, (wherey - 1) mod (hi(windmax)+2)); if a=#75 then gotoxy((wherex-1) mod (lo(windmax)+2), wherey); if a=#77 then gotoxy((wherex+1) mod (lo(windmax)+2), wherey); if a=#80 then gotoxy(wherex,(wherey + 1) mod (hi(windmax)+2)); until a=#27; clrscr; while keypressed do ruch; end. Zanim rozpoczniemy opisywanie tego programu powinniśmy sobie przypomnie ć, że klawisze kursorów i klawisze funkcyjne zwracaj ą dwa znaki. Pierwszy znak, to jest znak o kodzie ASCII zero. Drugi znak jest unikalny dla każdego z tych klawiszy. Dla klawisza F1 jest to znak o kodzie ASCII równym 59, dla F2 60, dla klawisza kursora góra 72, dó ł 80, lewo 75, prawo 77. Powyższy program służy do poruszania si ę kursorem w obrębie ekranu za pomoc ą klawiszy kursora. Najważniejsza cz ęść kodu znajduje si ę w procedurze ruch. W pętli repeat, która jest kończona w momencie naciśnięcia przez użytkownika klawisza Escape (kod ASCII 27), odczytywany jest jeden znak z bufora klawiatury. Jeśli ten znak ma warto ść zero, to odczytywany jest kolejny znak. Jeśli ten znak odpowiada klawiszowi F1, to ekran jest czyszczony przy pomocy procedury clrscr. Jeśli odpowiada klawiszowi F2, to wypisywana jest bieżąca pozycja kursora. Jeśli zosta ł naciśnięty który ś z klawiszy kursora, to kursor na ekranie jest przesuwany o jedn ą pozycj ę w gór ę, dó ł, lewo lub prawo. Dzieje si ę to za pomoc ą procedury gotoxy. Nowe współrzędne kursora są określane za pomoc ą funkcji wherex i wherey i operacji dodawania lub odejmowania. Prosz ę zauważy ć, że te operacje s ą wykonywane modulo liczba kolumn lub liczba wierszy na ekranie plus dwa. 11
9.Parametry wywołania programu W systemach operacyjnych takich jak Unix, Windows lub DOS istnieje możliwo ść przekazania programowi tzw. parametrów wywołania, czyli parametrów umieszczonych w wierszu polece ń. Przykładowo w systemie DOS lub po uruchomieniu programu cmd w systemie Windows XP możemy wywołać program dir z parametrem /w pisząc po prostu dir /w. Ciąg znaków znajdujący si ę za nazw ą programu traktowany jest jako jego parametr wywołania. Takich parametrów możemy przekaza ć programowi więcej, rozdzielając je znakami spacji lub tabulacji. W środowisku Turbo Pascala parametry wywołania programu możemy określi ć za pomoc ą opcji Run->Parameters. Aby odczyta ć w programie parametry jego wywołania musimy posłuży ć si ę dwiema funkcjami. Funkcja paramcount zwraca wartość typu word określając ą ile parametrów zostało przekazanych programowi w wierszu wywołania. Ta funkcja nie przyjmuje żadnego parametru. Drugą funkcj ą jest paramstr, która przyjmuje jeden parametr typu word. Tym parametrem jest indeks parametru wywołania programu. Funkcja zwraca warto ść typu string, która jest wartości ą tego parametru. Jeśli wywołując tę funkcj ę przekażemy jej zero, to zwróci ona nazw ę programu. Oto krótki, przykładowy program ilustrujący użycie tych funkcji: program parametry_wywolania; uses crt; procedure wypisz; var i:word; writeln('program o nazwie: ',paramstr(0)); writeln('zosta ł wywołany z następującymi parametrami: '); for i:=1 to paramcount do write(paramstr(i),' '); readln; 12
clrscr; wypisz; readln; end. 10. Numerowanie wierszy i kolumn w trybach tekstowych Wiersze i kolumny w trybach tekstowych s ą numerowane od jedynki. Kolumny s ą numerowane z lewa na prawo, tj. skrajnie lewa kolumna ma numer 1, skrajnie prawa numer maksymalny dla danego trybu, np. 80. Wiersze są numerowane od góry do dołu, tj. najwyższy wiersz ma numer 1, najniższy ma numer maksymalny dla danego trybu, np. 25. Sposób numerowania wierszy i kolumn pokazuje równie ż poniższa ilustracja. 1 1 80 ekran w trybie co80 25 13