A Graph Unit használata

 

Turbo Pascalban a grafikus képernyő használatát többek között a Borland Grafikus Interfészek, a *.bgi meghajtó programok biztosítják, melyeket a Tp\Bgi mappában helyeztek el. Ezek között találunk Hercules monitorra, színes, grafikus adapterre, EGA-ra, IBM8514-re írt csomagokat. Számunkra a legjobb meghajtó program az EGAVGA.BGI lesz. Ez alapból 640*480-as felbontást biztosít, 16 szín mellett. Win98-ig létezett még ennél is nagyobb felbontást biztosító svga256.bgi, de ezt a mai gépeken már eléggé reménytelen vállalkozás aktiválni. Pontosabban a gépeken belül a grafikus kártyák azok, amelyek felelősek a grafikus felület *.bgi-kel való kezelhetetlenségéért. Ha telepítéskor eltekintenénk a grafikus kártya meghajtó programjainak telepítésétől, akkor még némi remény lehetne ezek használatára, de ekkor a Windows grafikus képességeit jelentősen csorbítanánk, ami ugye nem lenne igazán nyerő dolog.

 

XP alatt és a legújabb grafikus kártyákon a BGI grafikát csak emulációval használhatjuk. Én a DOSBox programot szoktam erre használni. Az emulálás miatt elég lassú, de statikus grafikus kimenetekre, az alapok megismerésére még épp alkalmas. A DOSBox 0.73 egy ingyenes program, mely a Net-ről letölthető, telepítő állománya önkicsomagoló, az asztalon létrehozza az indító parancsikonját:

 

 

Erre kattintva a következőket láthatjuk:

 

 

A mount h c:\gmpascal\2010 parancsot már nekünk kell kiadni. A h jelenti majd a létrehozandó H:\ logikai meghajtót (olyan betűt válasszunk, amilyen betűjelű meghajtó a környezetben még nincs), a c:\gmpascal\2010 pedig azt a helyet jelöli, ahol a DOS-os környezetben futtatható, ez esetben grafikai programunk *.exe állománya található. H:+Enter-rel váltsunk át a létrehozott meghajtóra. A program futtatása: a program nevének beírása a parancssorba, majd Enter.

 

Írjunk programot, mely a Turbo Pascal Graph Unitjában megtalálható legfontosabb rajzeszközök használatát mutatja be.

 

Programunk neve GrDemo lesz. A szokásos Unitok mellett a Graph unitot is használatba kell venni. Írjunk egy GrInit nevű eljárást, mely végrehajtja a szükséges inicializálást. A grafikus környezetet egy grafikus driver (program, illetve kártya) és annak működtetési módja (felbontása, színhasználata) határozza meg. Mindkettő egy-egy egész számmal jellemezhető. Jelöljük ezeket: Gd és Gm-el. Egyszerű esetekben, egy bevezető programban, még azt sem kell feltétlen tudni, hogy ezek milyen egész értékeket vehetnek fel. A grafikus driver lekérdezésére a Detect függvény, az inicializálásra az InitGraph eljárás használható. Ezek szintaxisa a listából kiolvasható. A GraphResult a grafika inicializálásakor bekövetkezett esetleges hibákra utal, ha 0 az értéke, akkor az inicializálás sikeres.

 

A grafikus képernyő pontjainak koordinátái integer típusúak, azaz a címezhető pixeltartomány, mindkét koordinátára kb. -32 ezertől +32 ezerig tart (pontosabban -MaxInt-1-től +MaxInt-ig, ahol MaxInt=32767). A látható tartomány, tehát ami ebből a képernyőre esik, ennek csak töredéke, még ha a Windows-os környezetben igen jónak mondható 2048*1536-os felbontásra is gondolunk. A Graph unitot úgy írták meg, hogy a képernyőre nem kerülő pontokat egyáltalán nem kezeli, nem helyezi át látható helyre, nem ad hibaüzenetet, csak egyszerűen figyelmen kívül hagyja (grafikában ez a vágás). Még ha konkrétan nem is tudjuk, hogy mekkora felbontás áll rendelkezésünkre, sok mindent a unitra hagyatkozva rajzolgathatunk. Lássuk hogyan. Először is lekérdezhetjük a látható pontok X koordinátájának legnagyobb értékét, erre alkalmas GetMaxX függvény. Ugyanez az Y koordinátára a GetMaxY. Tároljuk ezeket az Xm illetve az Ym változókban. Nagyon hasznos lehet a képernyő közepén lévő pont két koordinátájának ismerete. Ezeket egész osztással kapjuk és tároljuk az Xk, Yk változókban. Gondolatban osszuk fel a képernyőt ezek segítségével négy részre. A bal felső negyedben pontokat, a jobb felsőben szakaszokat, a bal alsóban téglalap alakú kereteket, míg a jobb alsóban maximum 40 pixel sugarú köröket rajzolunk véletlen paraméterekkel (koordinátákkal, méretekkel és színekkel). Lássuk a programunk listájának első részét (több szakasza lesz):

 

Program GrDemo;

Uses NewDelay, Crt, CrtPlus, Graph;

 

Var Xm,Ym, Xk,Yk, X, I: Integer;

 

Procedure GrInit;

Var Gd,Gm: Integer;

Begin

  Gd:= Detect; InitGraph(Gd,Gm,'C:\Tp\Bgi');

  If GraphResult<>0 Then Halt;

  Xm:= GetMaxX; Ym:= GetMaxY;

  Xk:= Xm Div 2; Yk:= Ym Div 2;

End;

 

Begin

  GrInit;

  Randomize;

  Repeat

    PutPixel(Random(Xk),Random(Yk),Random(16));

    SetColor(Random(16));

    Line(Xk+Random(Xk),Random(Yk),Xk+Random(Xk),Random(Yk));

    Rectangle(Random(Xk),Yk+Random(Yk),

              Random(Xk),Yk+Random(Yk));

    Circle(Xk+Random(Xk)+40,Yk+Random(Xk)+40,Random(40));

  Until KeyPressed;

  CloseGraph;

End.

 

Egy pillanatban pedig így néz ki a futási kép:

 

 

A programban használt további eljárások és függvények:

 

- PutPixel: egy pont (pixel) színének beállítása. Három paramétere van, az első kettő a pont helyének két (X,Y) koordinátája, a harmadik a pont színe a végrehajtás után.

- SetColor: a rajzolás színének beállítása, egyparaméteres, a paraméter a szín neve, vagy kódja. A szín beállítása után a több pontból álló alakzatok pontjai (határoló pontjai) ilyen színűek lesznek.

- Line: szakaszrajzolás. Négyparaméteres eljárás, a paraméterek a két végpont két-két koordinátája X-Y sorrendben.

- Rectangle: keretrajzolás. Téglalap alakú, vízszintes és függőleges oldalakkal rendelkező keret. Négyparaméterű: a bal felső és jobb alsó csúcsainak két-két koordinátája.

- Circle: körrajzolás. Háromparaméterű, az első kettő a középpont két koordinátája, a harmadik a kör sugara.

- CloseGraph: a grafikus képernyő bezárása, mely során törlődik a grafikus képernyő tartalma.

 

Ez utóbbi eljárást hagyjuk a mindenkori programállapotban az utolsó eljáráshívásnak, a második fázisban ez előtt kell a következő sorokat elhelyezni:

 

...

KeyEmpty;

ClearDevice;

Repeat

  SetFillStyle(Random(8),Random(16));

  SetColor(Random(16));

  FillEllipse(Random(Xm), Random(Ym), Random(80),Random(80));

  Delay(100);

Until KeyPressed;

...

 

Az új sorok magyarázata:

 

- KeyEmpty: CrtPlus eljárás, törli a billentyűzet-puffer tartalmát, előkészítve a következő Repeat-Until szakaszt.

- ClearDevice: törli a grafikus képernyőt.

- SetFillStyle: a zárt grafikus elemek belsejének feltöltését beállító eljárás. Kétparaméteres, az első a feltöltés mintázatát adja, a második a belső rajzelemek színét. A 0-ás mintázat (ami valójában nem is minta) a háttért jelenti, az 1-es a sima feltöltést (solid), a többi valóban mintás, vonalakkal megoldva.

- FillEllipse: belsejében feltöltést tartalmazó, teljes ellipszis rajzolása. A körvonal színét a SetColor állítja be. Az ellipszis tengelyei függőleges és vízszintes irányúak (ferde nem lehet). Négyparaméteres eljárás, az első kettő az ellipszis középpontját határozza meg, a harmadik az X irányú főtengely hosszának a fele, a negyedik az Y irányúnak.

- Delay(100): egytized másodperces várakozás, ha egyébként is lassan változik a kép, akkor elhagyható.

 

És a futtatás egy pillanata:

 

 

 

A következő szakaszban rajzoljunk koncentrikus, különböző színű köröket a képernyő közepére. Előtte a képernyőt állítsuk be véletlen egyszínű háttérként. Szúrjuk be a következő sorokat a CloseGraph eljárás elé:

 

...

KeyEmpty;

SetFillStyle(1,Random(16));

Bar(0,0, Xm,Ym);

Varj;

For I:= 0 To 220 Do

Begin SetColor(I); Circle(Xk,Yk,I) End;

Varj;

...

 

Az új sor magyarázata:

 

- Bar: feltöltött téglalap rajzolása, az aktuális fillezési eljárással és színnel. Négy paramétere van, a szokásos csúcsok két-két koordinátája. Ebben a helyzetben a képernyőnek a háttérszínét (feketét) takarjuk el vele, és majd erre rajzolunk.

 

A többi sor nem grafika-specifikus, vagy a fentiekből már ismert. Nézzük mi lehet ennek a szakasznak a futtatási képe:

 

 

A következő kódrészlet két kör közös részének fillezését mutatja be:

 

...

SetFillStyle(1,14); Bar(0,0, Xm,Ym);

SetFillStyle(1,12); SetColor(1);

Circle(Xk-50,Yk,100); Circle(Xk+50,Yk,100);

Varj;

FloodFill(Xk,Yk,1);

Varj;

...

 

Az új eljárás:

 

- FloodFill: területfeltöltés az aktuális színnel és mintázattal. Háromparaméteres eljárás. Az első két paraméter egy olyan pontnak a két koordinátája, amely a fillezendő terület belsejében van. A harmadik egy színkód, amilyen színt ide beírunk, az olyan színnel körbevett tartományt tölti fel. Ha a tartomány nem zárt, akkor lehetséges, hogy az egész képernyő filleződik.

 

És az eredmény:

 

 

Most lássuk vonalak segítségével, hogyan lehet burkológörbét létrehozni. Egy kis kiegészítéssel pedig figyelő szempárt. Ismét a CloseGraph elé szúrjuk be:

 

...

ClearDevice;

SetColor(6);

For I:= 0 To 200 Do If Not Odd(I) Then

Begin

  Line(100+I,100, 300,100+I);

  Line(100,100+I, 100+I,300);

End;

SetColor(15); SetFillStyle(1,15); FloodFill(200,200,6);

SetColor(9); SetFillStyle(1,9); FillEllipse(200,200,65,65);

SetColor(0); SetFillStyle(1,0); FillEllipse(200,200,30,30);

For I:= 0 To 200 Do If Not Odd(I) Then

Begin

  Line(400,300-I, 400+I,100);

  Line(400+I,300, 600,300-I);

End;

SetColor(15); SetFillStyle(1,15); FloodFill(500,200,6);

SetColor(9); SetFillStyle(1,9); FillEllipse(500,200,65,65);

SetColor(0); SetFillStyle(1,0); FillEllipse(500,200,30,30);

Varj;

...

 

Nézzük mit kaptunk:

 

 

Az előző képekből a képernyő pixelben mért valós méreteire már lehet következtetni. Ezekből felbátorodva, néhány feltöltött téglalapot, illetve a 3d-s párját rajzoljunk a képernyőre, előtte azonban fehér téglalappal takarjuk el a hátteret. Újra a szokásos helyre szúrjuk be a következő sorokat:

 

...

SetFillStyle(1,15); Bar(0,0, Xm,Ym);

SetFillStyle(1,3); Bar(100,100, 300,400);

SetFillStyle(2,5); Bar(400,100, 600,400);

Varj;

 

SetFillStyle(1,15); Bar(0,0, Xm,Ym);

SetFillStyle(1,3); Bar3d(100,100, 300,400,20,False);

SetFillStyle(2,5); Bar3d(400,100, 600,400,20,True);

Varj;

 

Az új eljárás magyarázata:

 

- Bar3d: a három-dimenziót érzékeltető hasáb. Hatparaméteres. Az első négy a Bar eljáráséval megegyező értelmű. Az ötödik paraméter a térbeliséget megjelenítő mélységet adja meg, míg a hatodik arról dönt, hogy a felső téglalap körbe legyen-e rajzolva vagy sem. Ennek a hasábok egymás fölé helyezésénél van jelentősége (a nem látszó éleket nem rajzolja).

 

Lássuk a két futtatási képet, első a síkbeli fillezett téglalapok:

 

 

 

A második a térhatású hasábok:

 

 

 

Demonstrációs programunk utolsó fázisában egy kört fogunk mozgatni a képernyő bal széléről indulva a jobb széléig, közben a képernyő tetején a „Grafikus Demo Program” felírat lesz látható. Ennek a kódját is a szokásos helyre írjuk.

 

...

ClearDevice;

SetColor(Yellow);

SetTextStyle(0,0,3);

OutTextXY(10,100,’Grafikus Demo’);

OutTextXY(100,150,’Program’);

X:= 50;

For I:= 1 To 140 Do

Begin

  SetColor(5); SetFillStyle(1,5); FillEllipse(X,Yk,20,20);

  Delay(100);

  SetColor(0); SetFillStyle(1,0); FillEllipse(X,Yk,20,20);

  Inc(X,4);

End;

SetColor(5); SetFillStyle(1,5); FillEllipse(X,Yk,20,20);

Varj;

 

Először nézzük az új eljárásokat:

 

- SetTextStyle: szöveg stílusának beállítása. Háromparaméteres eljárás. Az első paraméter a fontkészlet kiválasztására szolgál (a DOSBox alatt eléggé korlátozott). A másodikkal az írás irányát adhatjuk meg (0: vízszintes, 1: függőleges). A harmadik paraméter a betűméretet határozza meg.

- OutTextXY: szöveg kiírása a grafikus képernyő megadható helyére (a CrtPlus WriteXY eljárásához hasonló). Az első két paramétere a szöveg helye, bal felső csúcsának két koordinátája, harmadik a kiírandó szöveg.

 

A mozgás úgy jön létre, hogy a feltöltött kört (hiszen a két ellipszissugár egyenlő, tehát az ellipszis egy kör) felrajzoljuk egy adott helyen, majd a háttérszínnel (0) újrarajzoljuk, ezáltal eltűnik, léptetjük a középpontot (Inc(X,4)), az új helyen az egészet újra megismételjük. Végül a cikluson kívül még egyszer felrajzoljuk, hogy ne tűnjön el véglegesen. És mozgás egy pillanata: