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: