Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them well
Java swing drawing - kreslenie v jave
1. Java SWING Drawing – Učíme sa kresliť v Jave
o Kresliť v JAVE môžeme viacerými spôsobmi. Využívať staršiu knižnicu awt alebo novší SWING.
Tu sa zameriame najmä na SWING, pričom metódy nie sú veľmi odlišné. Princíp ako vždy
takmer totožný. Najprv si vytvorme jednoduché okno pomocou metódy initOkno(), ktorú si
samozrejme definujeme my.
o Vytvorme si aj prázdne metódy initPlatno(), kde si neskôr nainicializujeme naše kresliace
plátno a taktiež initMys(), tam budeme registrovať poslucháčov a udalosti myši pri kreslení.
Tu si nastavíme kresliace plátno
Tu doplníme obsluhu klikania a ťahania myšou
o Momentálne sa po kompilácii a spustení zobrazí len samotné okno. Nebude obsahovať ešte
vyššie spomínane kresliace plátno, to si budeme vytvárať a konfigurovať práve teraz.
o Musíme sa zamyslieť či nám postačí bežný JPanel. V tomto prípade asi nie. Bude lepšie ak si
vytvoríme vlastnú triedu ktorá bude z JPanel dediť, pričom si ju rozšírime o potrebne metódy
pre vykresľovanie.
2. Samozrejme program neriešime za chodu (aj keď občas áno ). Chcem tým povedať máme
nejaký koncepčný model či UML, teda vieme približne kde a čo chceme mať.
Požiadavky sú nasledovné: Nech obsahuje daná trieda dve dátové položky x a y , ktoré budú
reprezentovať pozíciu v okne ( bližšie si ich ozrejmime pri samotnom kreslení ). Taktiež nech
v nej budú metódy na samotne kreslenie aby sme to mali pekne pokope...
Triedu si nazvime kresliacePlatno pričom nech je vnorenou triedou.
o Stretávame sa s metódou paintComponent(Graphics g) a ďalšou pomerne dôležitou
metódou repaint(). To o aké metódy sa jedna a aký je medzi nimi vzťah sa dočítame
v dokumentácii triedy JPanel. Ta nás ale odkáže na triedu JComponent z ktorej dedí:
Tam sa dozvieme, že metóda paintComponent obsahuje kód pre vykreslenie, presnejšie
vola metódu paint, ktorá sa vykoná zavolaním funkcie repaint(). Jednoduchšie povedané
aby sme vykreslili veci pod paintComponent musíme volať repaint().
o V tomto kroku si môžem deklarovať v rámci celej hlavnej triedy nove plátno vytvorene
z triedy kresliacePlatno, ktorú som si vyššie definoval. Pri deklarácii sa ešte reálne
v pamäti nevytvorí, len mi umožni s nim pracovať v rámci celého programu.
o Následne si ho v metóde initPlatno() aj reálne vytvorím a pridám do okna:
3. o V tomto kroku trochu odskočíme od programu a ukážeme si logiku, ktorou budeme
vykresľovať. V prvom rade budeme vykresľovať čiary (krivky). Tie sú tvorene sústavou
bodov navzájom poprepájaných. Presne takýmto spôsobom budeme aj vykresľovať
presnejšie vám to ozrejmi obrázok:
čiara 2
čiara 1
čiara 3
Každá čiara je samostatný objekt. Na začiatku nevieme koľko čiar nakreslíme. Môže ich
byť desať, sto alebo tisíc tento údaj proste nevieme. V takýchto prípadoch je rozumne
použiť dynamické pole ArrayList (Pozri jeho triedu v dokumentácii).
Každá z čiar predstavuje sled malých čiar(na úrovni dvoch pixlov), ktoré budeme po
jednom vykresľovať. Vykreslením niekoľko desiatok čí stoviek takýchto malých čiar (na
seba nadväzujúcich) dostaneme výslednú krivku. Ani tu nevieme povedať aká veľká bude
naša krivka, môže sa skladať aj z tisícky bodov. Aj tu použijeme dynamické pole, ale
v tomto prípade triedy Vector.
Touto logikou získame niekoľko výhod. Všetky nakreslene prvky máme niekde uložené
a v prípade napr. zmeny rozmeru okna sa mi komponenta nezmaže, len sa nanovo
prekreslí. S touto chybou, respektíve nedostatkom sa stretávame na internete v mnohých
návodoch. Užívateľ síce kreslí ale jemne zmení rozmer okna a komponenta zmizne
( preto nastavia setResizable(false)...) My ho ale potrebovať nebudeme... .Na tejto
logike je možné vybudovať plnohodnotný skicár.
o Teraz od teórie späť k programu. Začneme s ArrayList a to jeho deklaráciou v hlavnej
triede:
o V metóde initPlatno() si náš ArrayList – arl naozaj vytvoríme:
4. o Teraz si ozrejmime základné metódy ktoré budeme pri našom ArrayList pomenovanom
arl volať:
Ako som už vyššie spomínal, ArrayList uchováva polia Vektorov, pričom každé pole
predstavuje samostatnú krivku. Nemôžeme vykresliť všetko naraz. Najprv vykreslíme
jednu čiaru potom druhú až n-tú... Budeme postupovať cyklicky, konkrétne za pomoci
cyklu for. No z jeho definície vieme, že potrebujeme vedieť počet koľkokrát sa ma
vykonať. Tento údaj zistíme z veľkosti nášho ArrayList. Ak v ňom budú 2 čiary vieme, že sa
má vykonať len 2x a nie viac ani menej.
Index 0 Index 1 Index 2
Ukladám do objektu
triedy ArrayList, ktorý
predstavuje
dynamické pole.
Čiara 1 Čiara 2 Čiara 3 Objekty triedy Vector
Do indexu „0“ Do indexu „1“ Do indexu „2“
Každý jeden obsahuje
ArrayListu<Vector> množinu bodov
som umiestnil (x1,y1) ,(x2,y2) až
objekt triedy Vector (xN,yN)
o Pre vloženie objektu do dynamického poľa voláme metódu .add(object) čí Vloženie na
.add(index,object) koniec poľa
Vloženie na
konkrétne
miesto
o Pre zistenie veľkosti (počtu poli triedy Vector v ArrayList) budeme volať metódu .size():
Ta vracia počet elementov teda objektov ktoré boli doposiaľ pridané do dynamického
poľa. Pre vyššie uvedený obrázok by vrátila číslo 3. Pozor na indexy, síce posledný prvok
poľa je na indexe číslo dva no číslovanie poľa je od nuly!
o Pre získanie objektu uloženého do konkrétneho indexu voláme metódu .get(int index)
Návratová hodnota je typ pola ArrayList v našom prípade <Vector>.
Viac metód v prípade nášho ArrayListu (arl) volať nebudeme. Vystačíme si s 3 vyššie
spomenutými.
5. o Treba si uvedomiť za akých podmienok začíname kresliť, inak povedané kedy sa nám pridá prvý
objekt do nášho ArrayListu – arl. Pridanie objektov bude následkom klikania myšou:
Kliknutie myši
Načúva
Vytvorí sa mi nový objekt Kliknutie myšou sa vykoná
Udalosť
Action Listener Vector v poli ArrayList skôr ako ťahanie.
Každé kliknutie je teda
signálom vytvorenia nového
objektu v ArrayList.
Ťahanie myšou
Zavolá funkciu na vykreslenie Nový objekt = Nová čiara
Načúva všetkého čo je doposiaľ
uložené v dynamických
Action Listener poliach
o Nevýhodou je, že v prípade obyčajného klikania sa zbytočne vytvárajú nechcené objekty, to sa dá
ale ošetriť napr. vykreslením bodky pri kliknutí. Naplňme si teda metódu initMys() o nasledujúce
riadky vychádzajúce z obrázka vyššie:
o Metódu drawMyLine sme si už definovali na začiatku ale bez parametrov. Upravme si ju tak aby
preberala dva parametre a to získane súradnice X a Y ktoré nesú informáciu o počiatočnom bode
našej krivky (čiary).
o Teraz ku koncu budeme pracovať s metódou paintComponent, ktorú si naplníme potrebným
kódom, no skôr si vysvetlime podstatu objektu z triedy Vector, pretože ju budeme potrebovať.
Vieme, že ArrayList predstavuje pole objektov triedy Vector. Každý z objektov reprezentuje
samostatnú čiaru. Objekt triedy Vector je taktiež dynamickým poľom bodov x1,x2.....xN a
y1,y2.....yN.
Ak vykreslíme body ako malé čiarky pomocou metódy drawLine(x1,y1,x2y2) dostaneme krivku.
6. o Z dokumentácie triedy Vector zistime nasledovné:
Metóda pre pridanie prvku do dynamického poľa Vector je .add(E e)
kde E predstavuje typ predávaného objektu v našom prípade budeme pridávať bod, nato
využijeme triedu Point , ktorú si rozoberieme neskôr .
Metóda pre získanie elementu na určitom indexe poľa Vector je .elementAt(int)
Pozor pre získanie pôvodného objektu budeme musieť získaný objekt pretypovať na požadovanú
triedu. My budeme neskôr pretypovávať na (Point).
o Pre objekty triedy Points z dokumentácie vyčítame, že majú dve dátové položky a to X a Y , ktoré
budú v našom programe reprezentovať neraz spomínaný bod.
Pre vytvorenie nového bodu v poli Vector použijeme konštruktor s parametrami kde priamo
predáme požadované X a Y.
o Teraz si môžeme konečne dokončiť metódu paintComponent:
Získam objekt Vector na poslednej pozícii. Do získaného objektu pridám novy Point
Keďže veľkosť poľa je napr. 6 ale V praxi to znamená, že sa mi pridá ďalší
číslovanie poľa je od nuly preto musíme bod do poľa aktuálnej čiary, ktorú
pre získanie posledného prvku odčítať kreslím.
jednotku.
7. o Pre vykreslenie konkrétnej čiarky som už vyššie spomínal metódu drawLine(x1,y1,x2,y2). Viac
informácii o tejto metóde nájdeme v triede Graphics:
Metódu voláme cez objekt „e“, ktorý je z tejto triedy vytvorený.
Prvý cyklus for prechádza všetky objekty v ArrayList , pričom počet objektov získa cez metódu
.size(). Druhý cyklus for prechádza všetky Pointy v konkrétnom poli Vector veľkosť získa tiež
volaním metódy .size()
Výsledný kód programu je :
8. Nakoniec už len začať kresliť
Vypracoval: Dalibor Kundrát – javadebilnicek.daliborkundrat.sk