A Számítógépes Nyelvészeten korábban már szóba került a processing programozási környezet,
amelyet azért terveztek, hogy egyszerűen és hatékonyan lehessen
vizuális alkalmazásokat készíteni: egy java-ra épülő
(pontosabban, a java alá épülő) nyelvről van szó, amely a
számos grafikus megjelenítéssel kacsolatos feladatot megkönnyít
a beépített funciók segítségével.
Mint már akkor Zoli elmondta, nem egy
játékról van szó, hanem egy igen hatékony eszközről; ugyanezt
Ben Fry (a nyelv egyik atyja), Visualizing Data c. könyvében úgy
fogalmazza meg, hogy kész eszközök helyett a processing
építőkockákat ad -- egyedi problémákhoz ugyanis szinte
lehetetlen előre legyártott szabványos megoldásokat kitalálni.
A processing építőkockái valójában nem mások, mint a beépített funkciók -- valójában mindent a Java programnyelv végez, így nem is meglepő, hogy a szintaxis megegyező; és az sem, hogy bármikor "kinyúlhatunk" a processing nyelvből a Java funkcióihoz.
Mit szeretnénk tehát? A processing
két dologban jó: a vizualizációban és az interaktivitásban;
tehát -- hogy újra feltaláljuk a spanyolviaszt -- készítünk egy
primitív tag-felhőt. A megoldás annyiban nem lesz szabványos,
hogy kezdetben minden tag-et azonos méretben fogunk megjeleníteni;
csak utóbb, a az egér mozgatásával dönti el a felhasználó,
hogy mennyire szeretné "kiugrasztani" a gyakran előforduló
elemeket. Tehát, lesz egy "áttekintő nézetünk" és egy
"közelítő nézetünk".
Áttekintő nézet -- minden szó egyforma méretű
A gyakori szavakat kiemeltük
OK. A legegyszerűbb processing program
két funkcióból áll: a setup() és a draw(). A
setup() induláskor fut le egyszer, mint neve is mutatja, itt
érdemes elhelyezni minden kezdetben szükséges lépést. Pl., mi
itt állítjuk be a rajzfelület méretét (800x600), itt töltjük
be a betűtípust és itt olvassuk be az adat.txt-ből a
szavakat, amelyeket majd később ki szeretnénk írni a képernyőre.
Ezután a draw() funkció fut
le. Ez, mint neve is mutatja, alapvetően a megjelenítésért felel,
de természetesen bármi mást is elhelyezhetünk itt. Kiemelt
szerepe abban áll, hogy folyamatosan ismétlődik, vagyis miután a
program mindent kirajzolt, azonnal újra kezdi. Hogy mire jó ez? Ha
úgy képzeljük el a dolgok, mint az egymást követő filmkockákat,
egyből értelmet nyer a dolog: ha a két kocka közt nincs eltérés,
akkor nem veszünk észre semmit. Azonban ha van, akkor mozgásba
lendül a kép. Pl., ha egy kirajzolt pont koordinátáit minden
egyes funkció-híváskor megnöveljük egyel (x++;), akkor egy mozgó
pont lesz az eredmény. A processing környezet tehát azt a
könnyedséget adja, hogy nem kell magunknak megírnunk a "filmkockák
kirajzolásáért" felelős részt, elég csak a képekkel
foglalkoznunk.
Ezen a ponton érdemes megjegyezni,
hogy a processing komolyan veszi a globális és lokális változók
kérdését. Pl. a draw() funkción belül deklarált változók
minden egyes újrahíváskor elvesznek, így ha pl. a mozgó képpont
x koordinátáját az x változóban tárolnánk, azt
mindenképpen globálisan (vagyis a funkción kívül) kell először
deklarálnunk. A programunkban pl. ilyen az adat[], meret_szamlalo
vagy a lastMX.
Az interaktivitás beépítését a
processing azzal támogatja, hogy nagyon egyszerűvé teszi teszi a
különböző események figyelését. Pl. minden alkalommal, amikor
kattintunk, a mousePressed() funkció kerül meghívásra,
majd visszatér a program oda, ahol abbahagyta a futást. Ugyanez a
történik a mouseMoved() funkció esetén is. Az egérkurzor
koordinátáit a mouseX ill. a mouseY változókból
tudhatjuk meg.
Lássuk tehát, mi történik az
interaktív szövegfelhőnk kódjában. Először deklarálunk néhány
globális változót (mivel azt szeretnénk, hogy minden funkció
elérje ezeket). Ezután elindul a setup(), ami betölti az
adat.txt tartalmát (itt a szavak és a hozzájuk
tartozó értékek találhatók).
Végül elindul a draw(), amely
folyamatosan ismétlődik a program leálltáig. Először
kirajzoljuk az "irányító felületet" -- ez az a része a
képernyőnek, amelyen ha megmozdítjuk az egeret, akkor változik a
szavak mérete. Majd kiszámoljuk (egy gyökvonással), hogy hány
sorba és hány oszlopba rendezzük az adatainkat. Ezután elindítunk
egy ciklust, amely szép sorban kiírja megfelelő helyekre az adat[]
tömbben tárolt szavakat. Ha a szó maximális mérete nagyobb, mint
az aktuálisan beállított szövegméret, akkor az utóbbit
használjuk. Ha az aktuális szövegméret nagyobb, akkor a szó
maximális méretét használjuk.
Az utolsó két funkció az egér
mozgatását és az egérkattintást figyeli. Ha megmozdítjuk az
egeret ÉS a kurzor a "kezelőfelület" felett áll, akkor
növeljük vagy csökkentjük a szöveg méretét (attól függően,
hogy jobbra vagy balra húztuk az egeret). Ha kattintunk, akkor egy
új szöveg-elrendezést kérünk -- ezt egyszerűen úgy érjük el,
hogy megkeverjük az adat[] tömböt.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PFont f; | |
float szorzo=1.5; // ez a szam hatassal van a szoveg meretere | |
String[] adat = new String[100]; // itt taroljuk a szavakat | |
int[] meret = new int[100]; // itt taroljuk a szavakhoz tartozo gyakorisag-szamokat | |
void setup() { | |
size(800, 600); | |
smooth(); | |
f = loadFont("FreeSerifBold-48.vlw"); | |
// betoltjuk az adatokat es megkeverjuk | |
adat = loadStrings("adat.txt"); | |
Collections.shuffle(Arrays.asList(adat)); | |
// szetbontjuk a szora es a meretre | |
for (int i=0; i<adat.length;i++) { | |
String temp2[]=split(adat[i],"\t"); | |
adat[i]=temp2[0]; | |
meret[i]=int(temp2[1]); | |
} | |
} | |
// errol a szovegmeretrol kezdjuk a kirajzolast | |
int meret_szamlalo=18; | |
void draw() { | |
background(0); | |
// itt rajzoljuk ki az iranyito-teruletet | |
fill(255); | |
textFont(f,66); | |
rect(60,500,300,50); | |
text("<",40,540); | |
text(">",380,540); | |
fill(255,55,179); | |
//kiszamoljuk, hany sor es hany oszlop kell (tor mint tores) | |
int tor=floor(sqrt(adat.length))+1; | |
//kiszamoljuk a szavak kozti tavolsagot | |
int tavX=width/(tor+1); | |
int tavY=height/(tor+1); | |
textAlign(CENTER); | |
// kirajzoljuk a szavakat | |
for(int i=1;i<=tor;i++) { | |
for(int c=1;c<=tor;c++) { | |
int index=(c-1)*tor+(i-1); | |
if ( index <= adat.length-1) { | |
// ha az aktulisan beallitott szovegmeret nem nagyobb, mint a szo merete, akkor azzal rajzoljuk ki | |
if(meret_szamlalo < meret[index]) { | |
textFont(f,meret_szamlalo*szorzo); | |
} | |
// ha elerte a maximalis meretet, akkor annal maradunk | |
else { | |
textFont(f,meret[index]*szorzo); | |
} | |
//es vegul kiirjuk | |
text(adat[index],tavX*i,tavY*c); | |
} | |
} | |
} | |
} | |
// ez a funkcio figyeli, hogy modositunk-e a szavak mereten az eger mozgatasaval (az iranyito feluleten) | |
int lastMX,lastMY; | |
void mouseMoved() { | |
if (mouseX > 60 && mouseY > 500 && mouseX < 360 && mouseY < 550) { | |
if (mouseX > lastMX) { | |
meret_szamlalo=meret_szamlalo+8; | |
} | |
if (mouseX < lastMX) { | |
meret_szamlalo=meret_szamlalo-8; | |
} | |
} | |
lastMX=mouseX; | |
lastMY=mouseY; | |
} | |
// kattintassal tudjuk megkeverni a szavakat | |
void mousePressed() { | |
Collections.shuffle(Arrays.asList(adat)); | |
} |
Végül néhány megjegyzés:
1. A virtuális gép és a grafikus
felület sajnos lelassítja a program futását. Nagyon. Ezért az
egymásba ágyazott ciklusokkal, nagy tömbökkel és minden
hasonlóval csak nagyon óvatosan szabad bánni. Szerencsére a
bonyolultabb grafikus műveletekhez vannak beépített funkciók.
2. A Java típusai sokkal finnyásabbak,
mint mondjuk a python-éi. A float nem változik automatikusan
integerré, a string-et nem lehet csak úgy pikk-pakk karakterekké
szedni, stb... A tömbök sem túl rugalmasak: deklaráláskor el
kell döntenünk, milyen hosszúak legyenek, tehát nem tudjuk őket
a végtelenségig bővíteni. Többdimenziós tömbök léteznek, de
egy tömbnek csak egy eleme már nem lehet egy újabb tömb.
Dictionary/hash típus nincsen.
4. A programok könnyen konvertálhatók
java appletté, illetve az processing.js javascript könyvtár
segítségével közvetlenül böngészőből is futtathatók.
Folyt. köv.