Podstawy Programowania Wyk ad dwunasty: ł Modu crt i
Transkrypt
Podstawy Programowania Wyk ad dwunasty: ł Modu crt i
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 2 rozdzielczości , 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, Blue=1, określa kolor niebieski, Green=2 określa kolor zielony, Cyan=3 określa kolor turkusowy, Red=4, określa kolor czerwony, Magenta=5 określa kolor karmazynowy, Brown=6, określa kolor brązowy, LightGray=7, określa kolor jasnoszary, DarkGray=8 określa kolor ciemnoszary, LightBlue=9 określa kolor jasnoniebieski, LightGreen=10 określa kolor jasnozielony, LightCyan=11 określa kolor jasno turkusowy, LightRed=12 określa kolor jasnoczerwony, 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 okien3, 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 4 jeśli w buforze klawiatury znajduje się znak do odczytania . 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; begin clrscr; writeln('Pierwszy napis'); readkey; writeln('Drugi napis'); readkey; writeln('Trzeci napis'); readkey; 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 readkey; readkey; 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 5 procedurę nosound . 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; begin 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); end; procedure wyswietl(zx,zy:byte); var x,y:byte; begin x:=random(zx-20); y:=random(zy-20); okno(x,y,x+20,y+20); end; begin 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; begin gotoxy(x1,y1); window(x1,y1,x2,y2); for i:=black to white do begin 8 if i=0 then textbackground(white) else textbackground(black); if migaj then textcolor(i+blink) else textcolor(i); write('tekst'); end; while keypressed do readkey; repeat until keypressed; gotoxy(1,1); for i:=black to lightgray do begin textbackground(i); write('tekst'); delay(500); end; sound(1000); delay(500); nosound; end; begin clrscr; textmode(co40); demo(20,5,24,21,false); while keypressed do readkey; readkey; textmode(co80); demo(40,5,44,21,false); while keypressed do readkey; readkey; textmode(co40); demo(20,5,24,21,true); while keypressed do readkey; readkey; textmode(co80); demo(40,5,44,21,true); 9 while keypressed do readkey; readkey; 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 6 o podanych współrzędnych i utworzenie okna o określonych wymiarach . W oknie tym wypisywany jest wyraz „tekst” w kolejnych wierszach, za każdym 7 razem w innym kolorze . 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 readkey; 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; begin repeat a:=readkey; 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 begin a:=readkey; 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)); end; until a=#27; end; begin clrscr; while keypressed do readkey; 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; begin 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; end; begin 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 80 1 ekran w trybie co80 25 13