XIII. Kapcsolattartás a felhasználóval

A felhasználói felület a program azon része, amely segítségével a felhasználó a számítógéppel kommunikál. A felhasználói felület a mai napig az egyik legjobban kutatott és fejlesztett terület a számítástechnikában, ám ennek ellenére a mai napig nem alakultak ki a fejlesztés közben vakon követhetô szabályok. Az idôk folyamán természetesen kikristályosodtak bizonyos, sokak által követett szokások, módszerek. Ebben a leckében ezekkel az inkább csak irányelveknek tekintendô technikákról fogunk tanulni, amelyek elôsegíthetik a problémamentes kapcsolattartást a felhasználóval.

Súgás

A legtöbb felhasználó esetében igen sokat nyom a latban, ha a futtatott program konzekvensen ellátja használóját világosan fogalmazott, tömör üzenetekkel és információval mûködése során. A felhasználóval való kapcsolattartás egyik legfontosabb eleme a súgás, amikor is arról tájékoztatjuk a felhasználót, hogy most éppen milyen tevékenységet vagy adatot várunk tôle. A legtöbb ember egyszerûen átugorja a hosszú üzeneteket, ezért fogalmazzunk röviden és világosan. Ha mégiscsak terjedelmes információt kell közölnünk, akkor osszuk fel részekre, a legfontosabb részét jelenítsük meg és tegyük opcionálissá a maradék információ megtekintését. A ló másik oldalára esünk át, amikor a közölt információ túlságosan szûkszavú és a felhasználó nem igazán tudja eldönteni, hogy mit is akarunk. A legjobb módszer az arany középút megtalálására, ha valakit megkérünk, hogy tesztelje programunkat. Ügyeljünk az üzenetek megfogalmazására is. Kutatások bebizonyították, hogy a felhasználók kevésbé szeretik, ha úgy teszünk, mintha a számítógép emberi lény lenne. Sokkal jobb, ha például a "Szia! Azért vagyok itt, hogy elkészítsem az adóbevallásodat." üzenet helyett az "Ezzel a programmal az adóbevallást lehet elkészíteni." bejelentkezô üzenet jelenik meg adóbevallás készítésére alkalmas programunk indításakor. Amikor hiba történik, akkor pedig nem szabad a felhasználóval azt éreztetni, hogy a hiba miatta történt, hanem el kell neki magyarázni, hogy hogyan kerülheti el a jövôben a hasonló problémákat.

Segítségrendszer kiépítése

A REXX programok egyik fô jellemzôje, hogy többségük viszonylag rövid. Ez azt is jelenti, hogy a legtöbb esetben elég egy, a program használatát elmagyarázó üzenet és nincs szükség beépített segítségrendszerre. Természetesen elôfordulhatnak olyan esetek is, amikor érdemes a segítségek számára egy külön alrendszert tervezni. Az alábbiakban bemutatott példa kibôvítése az esetek többségében bôven elegendô. A példaprogram futtatásakor pótlólagos információt kapunk, ha a kérdôjelet viszünk be.

/* Minimális segítségrendszer */

DO FOREVER
	SAY 'Vezetéknév:'
	PARSE PULL nev
	SELECT
		WHEN nev = '?' THEN
			SAY 'Gépelje be a vezetéknevét!'
		WHEN nev = '' THEN
			SAY 'A vezetéknév szükséges információ!'
		OTHERWISE
			LEAVE
	END
END

EXIT

Hangeffektusok használata

A legeredményesebben talán a programokba beépített hangeffektusokkal vonhatjuk magunkra a felhasználók figyelmét. Jó dolog hangjelzést adni hosszabb futási idôt igénylô folyamatok végén, hibajelzések nyomatékosításaként, vagy egyéb figyelmeztetô üzenetek megjelenítésekor. A REXX-ben természetesen erre is van lehetôség, mivel a Beep függvény segítségével megszólaltathatjuk a PC hangszóróját, s a Beep paraméterei révén azt is megadhatjuk, hogy a jel frekvenciája (Hz) és idôtartama (ms) mekkora legyen. Az alábbi kétsoros kód például egy két tónusú hangjelzést ad:

Beep(250, 250)	/* 250Hz, 250ms */
Beep(150, 500)	/* 150Hz, 500ms */

Természetesen nem jó itt sem átesni a ló másik oldalára! Hacsak nem akarjuk valamilyen fontos dologra felhívni a figyelmet, akkor inkább ne használjunk hangokat. A "zajos" programokat nem szeretik a felhasználók, és elôbb utóbb megpróbálják majd programunkat elcsendesíteni.

Színek használata

A hangok mellett színekkel is "feldobhatjuk" programunkat. Az értelmetlen csicsázáson túlmenôen valódi többletértéket jelent, amennyiben a színeket konzekvensen használjuk. Ha például a hibaüzeneteket mindig piros színnel jelenítjük meg, akkor a felhasználó már tudni fogja, hogy valami rossz történt, mielôtt még elolvasná az aktuális hibaüzenetet. A színek kezelésére nincsenek külön REXX függvények, ugyanis a feladat tökéletesen megoldható az OS/2 parancssora által nyújtott eszközökkel. Alapesetben az OS/2-es ablak ANSI terminálemulációt nyújt. Az emuláció speciális ANSI vezérlôkarakterek segítségével befolyásolható. Ez azt jelenti, hogy speciális karakterláncok "megjelenítésével" letörölhetô például az ablak, vagy beállítható a háttér vagy a szöveg színe. Minden ANSI karakterlánc az escape karakterrel kezdôdik, amelynek 27, vagy pedig 1B a kódja hexadecimális számrendszerben. Az escape karaktert követô egyéb karakterek határozzák meg, hogy a parancs mit is csinálj. A [2J megadásával például töröljük a képernyôt:

SAY '1B'x || '[2J'

Mivel a vezérlôkarakterek észben tartása nem nagy élvezettel, ezért érdemes ôket megfelelôen elnevezett változókban tárolni és a kódok helyett ezeket a változókat használni.

A színek megadása már egy kicsit bonyolultabb:

SAY '1B'x || '[35;44m'

A [ után álló szám a szöveg, a ; után álló szám pedig a háttér színének a kódját jelenti. Az alábbi táblázatban összefoglaltuk az ANSI színek kódjait:

Szín:Szövegszín:Háttérszín:
fekete3040
piros3141
zöld3242
sárga3343
kék3444
magenta3545
cián3646
fehér3747

Gondolom nem lep meg senkit, hogy az alapértelmezés szerinti szövegszín a fehér, a háttérszín pedig a fekete. Ha valamelyik számot nem adjuk meg, akkor az alapértelmezett érték lesz továbbra is az érvényes. Ha a kódokat kombináljuk (amit a karakterláncok összefûzésével tehetünk meg), akkor hatásuk összeadódik. Amikor az elsô paraméternek 1-et adunk meg, az abban a pillanatban beállított szövegszín világosabb lesz. A 0-val visszatérhetünk az alapértelmezés szerinti szövegszínhez.

Több ANSI vezérlôkarakter is létezik a kurzor mozgatására, mi azonban csak egyet fogunk tárgyalni, ami a SAY utasítás mellékhatásnak köszönhetô. A SAY ugyanis mindig a sor elejére pozícionálja a kurzort, s ez bizonyos vezérlô karakterek esetében zavart okoz. A kurzor pozícionálására mi az '1B'x || [sor;oszlopH formátumú karakterláncot fogjuk használni. A színeket beállító karakterláncoktól eltérôen ebben az esetben H-ra végzôdik a parancs. A két paraméter adja meg a kurzor kívánt pozícióját. A képernyô bal felsô sarka az 1;1 koordinátájú pont, a többi pozíció az ehhez a ponthoz viszonyított eltérést adja meg. Most pedig lássunk egy példát a most tanultak használatára, amibôl minden egy csapásra világos lesz!

/* ANSI vezérlôkarakterek használata */

konyv. = ''
torles = '1B'x || '[2J'				/* képernyôtörlés	*/
feher_a_keken = '1B'x || '[37;44m'		/* fehér kék háttérrel 	*/
piros_a_keken = '1B'x || '[31;44m'		/* piros kék háttérrel	*/
vilagos = '1B'x || '[1m'			/* világosabb elôszín	*/
normalis = '1B'x || '[0m' || feher_a_keken	/* a normál szín	*/
segitseg_hely = '1B'x || '[3;1H' 		/* a segítségsor helye 	*/
vezeteknev_hely = '1B'x || '[5;1H'		/* a vezetéknév helye	*/
keresztnev_hely = '1B'x || '[7;1H'		/* a keresztnév helye	*/
utca_hely = '1B'x || '[9;1H'			/* az utca helye	*/
varos_hely = '1B'x || '[11;1H'			/* a város helyes	*/
segitseg_torles = segitseg_hely || Copies(' ', 80) || segitseg_hely

i = 0
DO FOREVER
	SAY feher_a_keken || torles 		
	SAY vilagos || Center('Hozzáadás a címjegyzékhez', 80) || normalis

	SAY segitseg_torles || Center('(Vezetéknév, vagy "kész", ha kész)', 80)
	SAY vezeteknev_hely || vilagos || 'Vezetéknév:' || normalis
	PARSE PULL valasz
	IF valasz = 'kész' THEN
		LEAVE
	i = i + 1
	konyv.i.vezeteknev = valasz

	SAY segitseg_torles || Center('(Keresztnév)', 80)
	SAY keresztnev_hely || vilagos || 'Keresztnév:' || normalis
	PARSE PULL konyv.i.keresztnev
	nev = konyv.i.vezeteknev konyv.i.keresztnev

	SAY segitseg_torles || Center('(Utca, házszám)', 80)
	SAY utca_hely || vilagos || 'Utca, házszám:' || normalis
	PARSE PULL konyv.i.utca
	
	SAY segitseg_torles || Center('(Város, irányítószám)', 80)
	SAY varos_hely || vilagos || 'Város, irányítószám:' || normalis
	PARSE PULL konyv.i.varos
END
konyv.0 = i

SAY normalis || torles
DO i = 1 TO konyv.0
	SAY ''
	SAY konyv.i.vezeteknev konyv.i.keresztnev
	SAY konyv.i.utca
	SAY konyv.i.varos
END

EXIT

A fenti program felhasználói adatokat kér be, s tárolja azokat. Minden egyes rekord bevitele után törli a képernyôt és kéri a következô személy adatait. Ha már nincs több adat, akkor a "kész" szó begépelésével léphetünk ki. A képernyô tetején minden esetben egy segítségsort is láthatunk, amelynek tartalma dinamikusan változik az éppen kitöltés alatt álló mezô jellegétôl függôen. A futás végén a program kilistázza az eltárolt adatokat. A segítségsort a képernyô alján is megjeleníthetjük, ekkor azonban ügyelni kell arra, hogy az információ megjelenítése után mindig újrapozícionáljuk a kurzort, különben a SAY utasítás a következô sor elejére pozícionál, ami a képernyô legördüléséhez vezet. Ha igazán biztosak akarunk lenni a dolgunkban, akkor programunkat a MODE utasítással kell kezdeni, hogy mi határozzuk meg a képernyô sorainak számát:

'mode 80,25'
infopos = '1B'x || '[25;1H'
curspos = '1B'x || '[5;1H'

info = 'Kérem a személy vezetéknevét!'
SAY infopos || info || curspos || 'Vezetéknév:'

Parancssorban megadható paraméterek használata

A programok egy része elfogad parancssorban megadott paramétereket is. Egy paraméter elvileg bármilyen adat lehet; az egyetlen korlátozás a parancsértelmezô által meghatározott maximális adathossz. Speciális paraméterek a kapcsolók (switch), amelyekkel a program viselkedését lehet befolyásolni. Az OS/2 dir parancsa például másképpen listázza ki a fájlokat és könyvtárakat, ha megadjuk a /w kapcsolót, mint anélkül. A kapcsolók elsô karaktere általában "/", vagy pedig "-", mivel így könnyen meg lehet különböztetni ôket a többi paramétertôl. A legjobb megközelítés az, ha mindkét fajtát támogatjuk programunkban. A kezdôkarakter után álló karakter vagy karakterek adják meg a kapcsoló jelentését. A legtöbb program nem tesz különbség a kis és nagybetûk között, bár erre nem érdemes alapozni, mivel vannak olyan alkalmazások, amelyek kénytelenek ezt a lehetôséget is kihasználni a megadható kapcsolók nagy száma miatt. Az alábbiakban egy olyan kódrészletet mutatunk be, amely alapjául szolgálhat a kapcsolók és paraméterek helyes kezelésének:

/* Kapcsolók és egyéb paraméterek feldolgozása */

PARSE ARG input

kapcsolok.0 = 0
parameterek.0 = 0

DO WHILE input <> ''
	PARSE VAR input szo input
	IF Left(szo, 1) = '/' | Left(szo, 1) = '-' THEN
		DO
			j = kapcsolok.0 + 1
			kapcsolok.j = Substr(szo, 2)
			SELECT
				WHEN kapcsolok.j = '?' | kapcsolok.j = 'h' THEN
					SAY 'Ez egy példaprogram!'
				OTHERWISE
					NOP
			END
			kapcsolok.0 = j
		END
	ELSE
		DO
			j = parameterek.0 + 1
			IF Left(szo, 1) = '"' THEN
				DO
					input = szo input
					PARSE VAR input '"' szo '"' input
				END
			parameterek.j = szo
			parameterek.0 = j
		END
END

SAY 'Kapcsolók:'
IF kapcsolok.0 = 0 THEN
	SAY 'Nem volt megadva!'
ELSE
	DO i = 1 TO kapcsolok.0
		SAY 'Kapcsoló'i': 'kapcsolok.i
	END

SAY 'Paraméterek:'
IF parameterek.0 = 0 THEN
	SAY 'Nem volt megadva!'
ELSE
	DO i = 1 TO parameterek.0
		SAY 'Paraméter'i': 'parameterek.i
	END

EXIT

A fô munkát a DO-WHILE hurok végzi, amely feldarabolja a parancssorban megadott adatot és minden egyes darabot megvizsgál, hogy nem egy kapcsolóról van-e szó. A SELECT utasítás ellenôrzi, hogy nem segítséget kért-e a felhasználó. Az idézôjelek közé tett paraméterekre is figyel a program, mivel elôfordulhat, hogy a megadni kívánt paraméterben szóköz is szerepel. A futás végén a program megjeleníti a megadott kapcsolókat és az egyéb paramétereket.

A bekért adatok ellenôrzése

A programozás egyik alapvetô szabálya a következôképpen hangzik: szemét be, szemét ki. Gyakori programozói hiba ugyanis azt feltételezni, hogy a felhasználó mindig korrekt adatokat visz be. Sajnos ez nem így van, ezért programunknak gondoskodni kell arról. hogy megvédje magát a szándékosan vagy esetleg csak véletlenül megadott rossz adatoktól, különben a program által generált kimenet nem az lesz, amire számítunk, vagy rosszabb esetben egyszerûen csak összeomlik az alkalmazás. Gyakori eset, hogy numerikus adatok bevitelekor nem ellenôrizzük, hogy valóban számokat kaptunk-e bemenetként. Ez szerencsére nagyon könnyen megoldható a már korábban ismertetett DATATYPE függvénnyel. Amikor egész számokra várunk, akkor ezt is ellenôrizni illik. Persze mint minden mást, az ellenôrzést sem kell túlzásba vinni. Ha például személyneveket várunk, akkor elég csak azt ellenôrizni, hogy a megadott adat legalább egy karakterbôl áll. Amikor összehasonlítjuk a bevitt adatot valamilyen, a programban tárolt adattal, akkor ne feledkezzünk meg arról sem, hogy meg akarjuk-e különböztetni a kis és nagybetûs eseteket. Ha nem, akkor érdemes az adatokat az összehasonlítás elôtt nagybetûs alakra hozni a TRANSLATE függvénnyel. Bizonyos esetekben elfogadhatunk rövidítéseket is a felhasználótól. Tipikus eset, amikor igen vagy nem választ várunk. Ilyenkor ahhoz vannak az emberek szokva, hogy elég az i vagy az n betûket megadni, és nem kell az egész szót begépelni. A rövidítések ellenôrzésére szolgál az Abbrev függvény:

Abbrev(információ, info [, hossz])

Ez a függvény egyszerûen összehasonlítja az info karakterláncot az információ karakterlánc elsô, vagy a hossz paraméter által megadott darabszámú karakterével, és ha ezek megegyeznek, akkor 1-et ad vissza, ellenkezô esetben pedig 0-át. Az Abbrev függvény különbséget tesz a kis és nagybetûk között is.

Defenzív programozás

A legtöbb helyzetben az a kívánatos, ha defenzíven programozunk. Ez azt jelenti, hogy programunknak számolni kell olyan esetekkel is, amelyek elvileg nem, vagy csak nagyon ritkán fordulhatnak elô. A bemeneti paraméterek ellenôrzése szükséges, azonban nem elégséges feltétele a defenzív programozásnak. Kívánatos például, hogy programunk CTRL-BREAK-kel történô megszakítására figyeljük, mivel ekkor programunkat ilyen esetben is kultúrált módon tudjuk befejezni. A megszakítás figyeléséhez be kell kapcsolni a már tanult SIGNAL ON HALT mechanizmust. Egy másik fontos dolog, hogy ellenôrizzük a futás során végrehajtott parancsok visszatérési értékeit. A parancsok végrehajtása ugyanis nem minden esetben sikerül, és ennek akár katasztrofális következményei is lehetnek:

'copy 'nagyon_fontos_adatfajl backupdir
'del 'nagyon_fontos_adatfajl

Ilyen esetben például nagyon fontos ellenôrizni a törlés elôtt, hogy a fontos fájl másolata valóban elkészült-e:

'copy 'nagyon_fontos_adatfajl backupdir
IF rc = 0 THEN
	'del 'nagyon_fontos_adatfajl

Bizonyos esetekben nem tudunk mit csinálni, ha egy parancs végrehajtása nem sikerül. Ilyenkor közölni kell a felhasználóval a rossz hírt, és ha van értelme, fel kell neki kínálni a lehetôséget, hogy a parancsot megismételtethesse.


REXX GYÍK:

K1. Hogyan kapcsolhatom be az ANSI terminálemulációt, ha az éppen ki van kapcsolva?
V1. Az ANSI ON illetve OFF paranccsal lehet az emulációt ki illetve bekapcsolni. Ha paraméter nélkül gépeljük be az ANSI parancsot, akkor válaszul megkapjuk az emuláció pillanatnyi állapotát.


Gyakorlatok:

1. Készítsen egy programot, amely összeadja a bevitt számokat és kijelzi az eredményt. A számok bevitelét az "=" begépelésével zárja le. Ellenôrizze, hogy a bevitt számok egész számok-e és ha nem, akkor adja meg a felhasználónak a hiba korrigálásának a lehetôségét!

Kádár Zsolt
1998. 06. 14.
[ Elôzô lecke | Következô lecke | Tartalom ]