5. KOMUNIKACJA PROGRAMU Z UŻYTKOWNIKIEM
5.1. Czytanie przez program danych wprowadzanych z klawiatury
Jedną z metod nadawania wartości zmiennym, zadeklarowanym w programie, polega na tym, że użytkownik wprowadza te wartości, korzystając z klawiatury. Zapis liczby zostaje czasowo zapamiętany w specjalnym obszarze pamięci zwanym buforem klawiatury, a następnie przypisany odpowiedniej zmiennej. Tego typu operacja nosi nazwę operacji wejściowej, lub operacji odczytu. W Turbo Pascalu do jej realizacji służy instrukcja o nazwie Readln (od ang. read − czytaj). Jej postać jest następująca:
Readln(X);
W tym zapisie Readln jest nazwą wywoływanej procedury odczytu, natomiast napisany w nawiasie argument tej procedury X jest nazwą zmiennej, do której ma być zapisana odczytana z klawiatury wartość. Zmienna X może być typu liczbowego, znakowego lub łańcuchowego. (Typ łańcuchowy zostanie omówiony w rozdziale 11).
Współpraca użytkownika z programem przy wykonywaniu instrukcji Readln przebiega, jak następuje:
Instrukcja zatrzymuje program, który czeka na reakcję użytkownika.
Użytkownik naciska kolejno klawisze, wpisując wartość, jaką chce nadać zmiennej X. Wpisywane znaki są widoczne na ekranie, co umożliwia kontrolę i poprawienie zapisu w przypadku pomyłki.
Gdy zapis wprowadzanej wartości jest kompletny, użytkownik naciska klawisz <Enter>.
Wprowadzona wartość zostaje przypisana zmiennej X. Dawna wartość X zostaje wymazana.
Program przechodzi do wykonania kolejnej instrukcji programu głównego.
W poniższym przykładzie pokażemy prosty program, którego jedynym zadaniem jest nadanie wartości trzem zmiennym.
Przykład 5.1. Program odczytujący z klawiatury wartości zmiennych
program Ex5_1; var X:Real; {deklaracja zmiennych} A,B:Byte; begin Readln(X); {czytanie wartości z klawiatury} Readln(A); Readln(B); end. |
Oprócz instrukcji Readln istnieje w Turbo Pascalu instrukcja Read o podobnym działaniu. Nie zalecamy jednak jej stosowania do czytania danych z klawiatury, ponieważ instrukcja ta po naciśnięciu klawisza <Enter> pozostawia w buforze klawiatury oprócz odczytanej wartości jeszcze dwa znaki: #13 i #10. Może to stać się przyczyną pewnych problemów przy kolejnych odczytach danych z klawiatury.
Za pomocą jednej instrukcji Readln można wprowadzić z klawiatury dane do dowolnej liczby zmiennych różnych typów. Instrukcja wywołania ma wtedy odpowiednio więcej argumentów, tak jak w przykładzie 5.2. Argumenty oddziela się przecinkami.
Przykład 5.2. Odczytywanie z klawiatury kilku wartości jedną instrukcją
program Ex5_2; var X:Real; {deklaracja zmiennych} A,B:Byte; begin Readln(X,A,B); {czytanie wartości z klawiatury} end. |
Gdy instrukcja Readln ma wiele argumentów, to po wprowadzeniu każdej kolejnej wartości trzeba nacisnąć klawisz spacji lub klawisz <Enter> a po wprowadzeniu ostatniej wartości - klawisz <Enter>. Łatwo wtedy o pomyłkę. Szczególnie duże prawdopodobieństwo błędu występuje, gdy argumenty procedury są różnych typów.
Przy wprowadzaniu danych z klawiatury należy przestrzegać następujących zasad:
Nie używać instrukcji Read, lecz Readln,
zastępować wieloargumentowe wywołania procedury Readln sekwencją kilku wywołań jednoargumentowych
unikać zestawiania w jednej instrukcji argumentów różnych typów
nigdy nie łączyć w wywołaniu procedury Readln argumentów liczbowych z argumentami znakowymi lub łańcuchowymi.
5.2. Odczytywanie znaków wprowadzanych z klawiatury za pomocą funkcji Readkey
Jeżeli chcemy odczytać z klawiatury pojedynczy znak, wprowadzony przez użytkownika, to często zamiast procedury Readln wygodniejsza okazuje się specjalnie do tego przeznaczona bezargumentowa funkcja Readkey (ang. read key - czytaj klawisz). Ponieważ Readkey jest funkcją, a nie procedurą, to wywołuje się ją następująco:
Z:=Readkey;
Funkcja Readkey jest wywołana po prawej stronie instrukcji przypisania. Po lewej stronie instrukcji znajduje się nazwa zmiennej typu Char, w której chcemy przechować wprowadzony z klawiatury znak. Działanie instrukcji przypisania i znaczenie operatora ':=' będą dokładnie wyjaśnione w rozdziale 6. Tutaj wystarczy stwierdzić, że operator ten powoduje przesłanie wartości wyrażenia wpisanego po prawej stronie do zmiennej występującej po lewej stronie instrukcji. W naszym przypadku oznacza to, że znak, pobrany przez funkcję Readkey z bufora klawiatury, zostanie zapisany w zmiennej znakowej Z.
Działanie funkcji Readkey jest zupełnie inne, niż działanie procedury Readln. Wykonanie pokazanej powyżej instrukcji przypisania, mającej po prawej stronie wywołanie Readkey, przebiega, jak następuje:
Funkcja Readkey zatrzymuje program, który czeka na reakcję użytkownika.
Użytkownik naciska wybrany klawisz znakowy.
Funkcja Readkey pobiera odpowiedni znak z bufora klawiatury.
Pobrany znak zostaje przekazany do zmiennej, której nazwę wpisano po lewej stronie instrukcji przypisania.
Program przechodzi do wykonania swojej kolejnej instrukcji.
Zwróćmy uwagę, że w przypadku użycia funkcji Readkey użytkownik nie widzi na ekranie znaku, który wprowadził z klawiatury. Ponadto nie ma potrzeby naciskania klawisza <Enter> - program wznawia swoje działanie bezpośrednio po naciśnięciu klawisza - zobacz pkt. 2 opisanego procesu.
5.3. Użycie Readln lub Readkey do zatrzymania programu.
W trakcie uruchamiania programu, lub usuwania z niego błędów logicznych, wygodnie jest zatrzymać jego działanie. Wtedy w oknie edycyjnym można bezpośrednio zaobserwować dotychczas wyprowadzone na ekran dane, bez potrzeby wykonywania polecenia Debug/Output lub Debug/User screen.
Do zatrzymania programu nadają się instrukcje Readln oraz Readkey, ponieważ po ich napotkaniu program zatrzymuje się, czekając na reakcję użytkownika. W przypadku, gdy zastosowano instrukcję Readln, program wznawia działanie po naciśnięciu klawisza <Enter>. Natomiast w przypadku użycia instrukcji Readkey program wznawia działanie po naciśnięciu dowolnego klawisza znakowego lub <Enter>. Ponieważ jedynym zadaniem tych instrukcji jest tutaj zatrzymanie programu, nie muszą one czytać danych z klawiatury. Dlatego stosujemy w tym przypadku instrukcję Readln bez argumentów, a Readkey wywołujemy poza instrukcją przypisania, tak jak pokazano w przykładzie 5.3.
Przykład 5.3. Zatrzymywanie programu za pomocą Readln lub Readkey
begin {-------} {-------} Readln; end.
|
begin {-------} {-------} Readkey; end. |
Zatrzymanie programu funkcją Readkey nie zawsze jest skuteczne. Program zatrzymuje się tylko wtedy, gdy bufor klawiatury jest pusty. Gdy znajduje się w nim jakiś znak, Readkey pobierze go bez czekania na naciśnięcie klawisza.
Wyprowadzanie danych na ekran za pomocą instrukcji Write, Writeln
Chcąc wydać komputerowi polecenie wyprowadzenia jakichś danych na ekran monitora, wpisujemy w odpowiednim miejscu programu instrukcję:
Write(A1,A2, ... An); lub: Writeln(A1,A2, ... An);
Instrukcje te powodują wywołanie odpowiedniej procedury standardowej, której zadaniem jest wyprowadzenie danych na ekran. Kolejny znak danej jest zawsze pisany na tej pozycji ekranu, w której aktualnie znajduje się migająca kreska zwana kursorem. Po wypisaniu danych przez Write, kursor zajmuje pozycję za ostatnim napisanym znakiem, natomiast po wykonaniu instrukcji Writeln kursor przesuwa się na początek następnego wiersza ekranu. Jest to jedyna różnica w sposobie działania obu instrukcji.
Argumenty A1..An służą do określenia danych, które są kolejno wyprowadzane na ekran. Liczba argumentów jest dowolna i mogą być one różnych typów, przy czym dozwolone są jedynie typy: liczbowe, znakowy, logiczny, łańcuchowy. Przy próbie wypisania wartości innego typu pojawi się błąd kompilacji z komunikatem:
Error 64: Cannot Read or Write variables of this type.
Rodzaj wyprowadzanych danych może być rozmaity. Argument Ai może być:
stałą jawną tj. konkretną liczbą, wartością logiczną (True, False), znakiem, napisem,
nazwą stałej, wcześniej zdefiniowanej w programie,
nazwą zmiennej,
wyrażeniem,
wywołaniem funkcji.
Stałe jawne są wyprowadzane na ekran bez zmian. W przypadku stałych definiowanych lub zmiennych, instrukcja wypisze definiowaną wartość stałej lub pobraną z pamięci aktualną wartość zmiennej. Gdy argumentem jest wyrażenie, instrukcja Write lub Writeln obliczy jego wartość i na ekran zostanie wyprowadzony końcowy wynik. Jeśli argument jest funkcją, to zostanie ona wywołana, a na ekranie ukaże się zwracana przez nią wartość.
W przykładzie 5.4 pierwszym argumentem instrukcji Writeln jest stała łańcuchowa 'Sqrt(2)+1=', która zostaje wyprowadzona bez zmiany. Drugim argumentem jest natomiast wyrażenie Sqrt(2)+1, które zawiera wywołanie funkcji Sqrt, obliczającej pierwiastek kwadratowy danej liczby. (Nazwa Sqrt jest skrótem od ang. square root - pierwiastek kwadratowy). Po obliczeniu wartości wyrażenia, jego wartość zostaje pokazana na ekranie w notacji zmiennoprzecinkowej, gdzie „E+00” oznacza „pomnożone przez 100 ”. Symbol `_` wskazuje położenie kursora, który przeskoczył na początek następnego wiersza.
Przykład 5.4. Program wykorzystujący instrukcję Writeln
begin Writeln('Sqrt(2)+1=',Sqrt(2)+1); end.
{Na ekranie pojawi się tekst: Sqrt(2)+1=2.4142135624E+00 _ } |
Parametry “długość” i “liczba pozycji”
Każdy z argumentów instrukcji Write, Writeln może występować łącznie z parametrem całkowitym o nazwie długość, oznaczonym tu symbolem d. Parametr ten wstawia się do instrukcji pisania bezpośrednio za argumentem, po dwukropku, jak poniżej
Writeln(X:d);
Parametr d narzuca liczbę pozycji znakowych, które zajmie na ekranie kod wyprowadzanej wartości X. Jeżeli d jest większe, niż liczba znaków potrzebna do wyprowadzenia formatu danej X, to na początek zostaną doklejone spacje, tak by całkowita liczba znaków zajmowanych przez wyprowadzoną daną wyniosła d. Jeżeli parametr d jest mniejszy od długości lub równy długości początkowej wyprowadzanej danej, to zostanie on po prostu zignorowany. Program z przykładu 5.5 pokazuje, w jaki sposób można wykorzystać omawiany parametr, by wyjustować (tj. wyrównać do prawej strony) wyprowadzane kolejno pozycje tabeli. W pierwszej kolumnie tabeli program pisze pięć wartości całkowitych, a w drugiej - kwadraty tych wartości, obliczone przez standardową funkcję Sqr (ang. square - kwadrat).
Przy wyprowadzaniu liczb rzeczywistych (np. typu Real) przydaje się drugi parametr o nazwie liczba pozycji, który będziemy oznaczać symbolem p. Wstawia go się jako drugi, po parametrze d, jak poniżej:
Writeln(X:d:p);
Jak pamiętamy, Turbo Pascal standardowo wyprowadza liczby rzeczywiste w formacie zmiennoprzecinkowym (mantysa z 10 pozycjami po kropce dziesiętnej i dwucyfrowy wykładnik potęgi liczby 10), tak jak to pokazano w przykładzie 5.4. Stosując parametr p, wymuszamy wyprowadzenie liczby rzeczywistej w postaci tradycyjnej, przy czym wartość p określa liczbę miejsc po kropce dziesiętnej. Przy zmniejszaniu p program samoczynnie zaokrągla wartość najmłodszej pozycji dziesiętnej. Pamiętajmy, że parametr p można stosować tylko do wartości typu rzeczywistego (np. Real) i jedynie łącznie z parametrem długość. Parametry d i p zastosowano w przykładzie 5.6 do wyprowadzenia, w postaci tradycyjnej i z różną liczbą miejsc po kropce, wartości pierwiastka kwadratowego z liczby 3.
Przykład 5.5. Program wykorzystujący parametr „długość”
begin Writeln(0:2,Sqr(0):10); Writeln(10:2,Sqr(10):10); Writeln(20:2,Sqr(20):10); Writeln(30:2,Sqr(30):10); Writeln(40:2,Sqr(40):10); end.
{Na ekranie pojawi się tekst: 0 0 10 100 20 400 30 900 40 1600 _ }
|
Przykład 5.6. Wykorzystanie parametrów „długość” i „ liczba pozycji”
begin Writeln(Sqrt(3)); Writeln(Sqrt(3):12:1); Writeln(Sqrt(3):12:2); Writeln(Sqrt(3):12:3); Writeln(Sqrt(3):12:4); Writeln(Sqrt(3):12:5); Writeln(Sqrt(3):12:6); end.
{Na ekranie pojawi się tekst: 1.7320508076E+00 1.7 1.73 1.732 1.7321 1.73205 1.732051 _ } |
Struktura powierzchni ekranu i okno robocze w trybie znakowym
Po włączeniu Turbo Pascala domyślnie włącza się znakowy tryb współpracy z ekranem. W trybie tym mamy do dyspozycji na ekranie okno robocze zawierające 2000 pól znakowych, ułożonych w 80 kolumn i 25 wierszy. Kolumny mają numery od 1 do 80. Wiersze są ponumerowane od 1 do 25, przy czym numer 1 ma wiersz położony u góry ekranu. Każdemu z pól znakowych można przypisać pięć wielkości:
położenie (X,Y), gdzie X- numer kolumny, Y - numer wiersza
rodzaj znaku
kolor tuszu
kolor tła
Wszystkie znaki pisane są domyślnie jasnoszarym kolorem na czarnym tle.
Wielkość okna roboczego można zmienić, korzystając z instrukcji:
Window(X1,Y1,X2,Y2);
w której argumenty X1, Y1 określają położenie górnego lewego rogu nowego okna, a argumenty X2, Y2 - położenie dolnego prawego rogu tego okna. Na przykład instrukcja Window (21,6,60,20) wyznacza symetryczne względem środka ekranu okno robocze o rozmiarze 40 kolumn i 15 wierszy. Od tej chwili, wyprowadzany na ekran tekst będzie pisany wyłącznie w ramach nowego okna, przy czym współrzędne każdego znaku będą określane w stosunku do nowego okna. Wobec tego numery kolumn nowego okna leżą w zakresie 1..40, a numery wierszy w zakresie 1..15. Chcąc powrócić do pełnego okna roboczego, musimy wykonać instrukcję Window (1,1,80,25).
Sposoby sterowania położeniem kursora
Położenie kursora jest bardzo ważne, bo od niego zawsze zaczyna się wypisywanie na ekranie kolejnego łańcucha znaków przez instrukcje pisania Write lub Writeln. Po napisaniu każdego kolejnego znaku, kursor przesuwa się o jedną pozycję w prawo. Jeśli zajmował ostatnią, 80. pozycję wiersza, zostanie przesunięty na pozycję 1 następnego wiersza. Jeżeli jednak wiersz, w którym kursor zajmował ostatnią kolumnę, jest 25. wierszem ekranu, to cały tekst przemieści się o jeden wiersz do góry, a u dołu ekranu utworzy się pusty wiersz, na którego początku znajdzie się kursor. Jest to tak zwane przewijanie ekranu.
Jak już wyjaśnialiśmy, położenie kursora zmienia się po wykonaniu instrukcji Writeln - przechodzi on wtedy na początek następnego wiersza.
Położenie kursora zmienia się również po oczyszczeniu aktualnego okna roboczego ekranu. (Przez oczyszczenie rozumie się zapełnienie okna samymi znakami spacji). Do oczyszczenia ekranu służy zawarta w module Crt, instrukcja wywołania bezargumentowej procedury:
Clrscr;
Instrukcja Clrscr, poza wyczyszczeniem ekranu (ang. Clear screen - wyczyść ekran), ustawia kursor w położeniu (1,1), to jest w lewym górnym rogu aktualnego okna roboczego.
Wymienione powyżej możliwości przemieszczania kursora nie pozwalają na swobodne sterowanie jego położeniem przez program. Potrzebna jest jeszcze instrukcja, która ustawia kursor w określonej pozycji ekranu. Turbo Pascal ma ją w swoim module Crt w postaci:
Gotoxy(X,Y);
Argumenty X, Y są całkowite i dodatnie. Określają one pozycję, na której chcemy umieścić kursor, przy czym X jest numerem kolumny, a Y - numerem wiersza okna roboczego. Przedziały dozwolonych wartości X, Y wynikają z rozmiarów okna. Jeżeli wpiszemy zerową lub zbyt dużą wartość argumentu, to instrukcja Gotoxy nie zadziała.
Wspólnie z instrukcją Gotoxy często stosuje się dwie bezargumentowe funkcje standardowe o nazwach Wherex, Wherey, należące również do modułu Crt. Funkcja Wherex zwraca po wywołaniu numer kolumny, a Wherey - numer wiersza, zajmowanych aktualnie przez kursor. Chcąc na przykład przejść do kolumny 10 w ramach tego samego wiersza, w którym aktualnie jest kursor, zastosujemy instrukcję:
Gotoxy(10,WhereY);
Chcąc zaś przejść do wiersza 3, pozostając w tej samej kolumnie, użyjemy instrukcji:
Gotoxy(Wherex,3);
W tablicy ASCII jest kilka znaków sterujących kursorem. Te znaki to #8, #10, #13. Wyprowadzenie ich za pomocą instrukcji Write skutkuje odpowiednią zmianą położenia kursora:
Write(#8); {Kursor cofa się o jedną pozycję w lewo.}
Write(#10); {Kursor zostaje przesunięty o jedną pozycję w dół.}
Write{#13}; {Kursor przechodzi na początek aktualnego wiersza.}
Zauważmy, że instrukcje:
Write(#13,#10); Writeln;
działają jednakowo - każda z nich przemieszcza kursor na początek następnego wiersza okna roboczego.
Ustawianie kolorów tuszu i tła
Każdy znak na ekranie pisany jest określonym kolorem tuszu na określonym tle. Po włączeniu Turbo Pascala ustawiają się domyślnie: jasnoszary kolor tuszu i czarny kolor tła. Te kolory można jednak zmienić programowo za pomocą procedur Textcolor, która ustawia kolor tuszu, oraz Textbackground, która ustawia kolor tła. Ich instrukcje wywołania wyglądają, jak następuje:
Textcolor(Stała_koloru);
Textbackground(Stała_koloru);
Stałe koloru zestawiono w tabeli 5.1.
Tabela 5.1. Stałe kolorów tła i kolorów tuszu
Nazwa stałej |
Wartość stałej |
Kolor |
Zastosowanie |
Black Blue Green Cyan Red Magenta Brown Lightgray |
0 1 2 3 4 5 6 7 |
Czarny Niebieski Zielony Turkusowy Czerwony Purpurowy Brązowy Jasnoszary |
Tło, tusz Tło, tusz Tło, tusz Tło, tusz Tło, tusz Tło, tusz Tło, tusz Tło, tusz |
Darkgray Lightblue Lightgreen Lightcyan Lightred Lightmagenta Yellow White Blink |
8 9 10 11 12 13 14 15 128 |
Ciemnoszry Jasnoniebieski Jasnozielony Jasnoturkusowy Jasnoczerwony Jasnopurpurowy Żółty Biały Daje efekt migotania |
Tusz Tusz Tusz Tusz Tusz Tusz Tusz Tusz Tusz |
Jak widać, do dyspozycji jest osiem kolorów tła. Liczba kolorów tuszu jest dwukrotnie większa, ponieważ oprócz takiej samej palety kolorów, jakie mamy dla tła, występują jeszcze ich „jasne” odpowiedniki. Specjalne znaczenie ma stała Blink o wartości 128. Jej arytmetyczne dodanie do argumentu procedury Textcolor spowoduje migotanie tekstu na ekranie.
Instrukcje Textcolor i Textbackground nie zmieniają kolorów tekstu pisanego na ekranie przed ich wykonaniem, natomiast zmieniają kolor tuszu lub tła wszystkich znaków wyprowadzanych po ich wykonaniu. W dowolnym miejscu programu można przywrócić kolory domyslne, wykonując instrukcję:
Normvideo;
Od tej chwili wszystkie znaki będą pisane jasnoszarym tuszem na czarnym tle.
W przykładzie 5.7 pokazano program, w którym zastosowano większość omówionych w rozdziale 5 instrukcji.. Zachęcamy do samodzielnego przeanalizowania działania tego programu. W analizie programu pomocne są komentarze, umieszczone w nawiasach klamrowych. Kompilator pominie je przy tłumaczeniu programu na język wewnętrzny.
Przykład 5.7. Program, który czyta wiek z klawiatury i wita użytkownika
program Ex5_7; uses Crt; {Deklaracja modułu}
var Wiek:Byte; {Deklaracja zmiennej}
begin Clrscr; {Czyszczenie całego ekranu} Write('Ile masz lat? '); {Użytkownik jest pytany o wiek.} Readln(Wiek); {Użytkownik wprowadza wiek.} Clrscr; {Usuwanie tekstu dialogu z użytkownikiem} Window(21,9,60,15); {Określenie nowego okna roboczego} TextBackground(Green); {Ustawienie zielonego tła} Clrscr; {Dopiero teraz nowe okno staje się zielone.} Textcolor(Yellow); {Ustawienie żółtego koloru tuszu} Gotoxy(12,4); {Ustawienie kursora w pozycji początkowej} Write('Witaj, ',Wiek:2,'-latku!'); {Pisanie tekstu powitania} Readln; {Program zatrzymany, czeka na <Enter>.} Window(1,1,80,25); {Przywrócenie pełnego okna roboczego} Normvideo; {Powrót do domyślnych kolorów tuszu i tła} Clrscr; {Końcowe czyszczenie ekranu} end.
{Jeśli np. Wiek=27, program wyprowadzi w oknie roboczym, żółtymi literami na zielonym tle, następujący tekst:
Witaj, 27-latku! _ }
|
24