9. diel - Kreslenie na Graphics v Java Swing
V predchádzajúcom cvičení, Riešené úlohy k 4.- 8. lekcii Java Swing, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.
V minulom dieli seriálu tutoriálov o tvorbe formulárových aplikácií v Java Swing sme doprogramovali pripomienkovej narodenín. Vyskúšali sme si na ňom základné formulárové prvky a tiež modely a prácu s chybovými stavmi. Už vieme vytvoriť pomerne sofistikované aplikácie. Dnešné lekcii budeme venovať kreslenie.
Kreslenie na Graphics
Vytvoríme aplikáciu, ktorá má za úlohu zastrešiť predaj vstupeniek do kina. Ako vieme, v sály je veľa sedadiel a pracovník kina by mal v aplikácii vidieť, ktorá sedadlá sú už obsadená. Možno by vás napadlo naklikať pre sedadlá labely. Ak by však kino malo 15 radov a každá rada 30 sedadiel, máme to 450 labelov. Asi tušíte, že existuje lepšia cesta, než začať búšiť JLabel1, JLabel2 ... A ako by sa potom obsluhovali? V prípade, že potrebujeme vykresliť niečo náročnejšieho, než len jeden alebo dva obrázky, využijeme Graphics. To spočíva v tom, že na formulár umiestnime nejakú komponent (najčastejšie JPanel alebo Canvas) a na jej plátno budeme vykresľovať to, čo potrebujeme.
Aplikáciu značne zjednodušíme, nie je potrebné aby bola zložitá. Bude vedieť zobraziť len jeden sála, ktorý bude spočiatku prázdny. Užívateľ naklikať myšou obsadená sedadla a potom stlačí tlačidlo Uložiť, ktoré do zvolenej lokácie uloží jednoduchý txt súbor s informáciou o obsazenosit sály. Ukladanie si skúsime preto, aby sme sa naučili pracovať s dialógmi.
Návrh formulára
Vytvorte si novú Java Application bez hlavnej triedy, pridáme do nej nový KinoJFrame, titulok mu nastavíme potrebné na "Evidencia kinosály". Cez väčšinu formuláre natiahnite JPanel (je v palete v sekcii Swing Containers), ktorý pomenujeme platnoJPanel. Pod JPanel príde JButton s menom ulozitJButton a textom "Uložiť".
Logická vrstva
Asi vás neprekvapí, že k aplikácii pridáme triedu kinosály. Bude mať jeden privátne atribút, ktorým bude dvojrozmerné pole sedadiel. Ak ste s 2D poľom ešte nepracovali, tak si ho môžete predstaviť ako tabuľku. Jednorozmerné (klasické) pole je vlastne len jeden riadok. S 2D poľom potom pracujeme úplne rovnako, ako s jednorozmernými, len musíme uviesť dve súradnice (X a Y). Niektoré jazyky majú na 2D pole priamo dátový typ, v Jave to tak nie je a ak chceme 2D poľa, urobíme jednoducho pole polí. Máme teda pole (riadok) a v každej "priehradke" tohto poľa je ďalšie pole (stĺpec). Vo finále máme teda tabuľku.
class Kinosal { private boolean[][] sedadla = new boolean[30][15]; }
Sedadlá sú typu boolean, pretože nás zaujíma len či je voľné alebo obsadené. 30 je šírka poľa, 15 jeho výška.
Do triedy ešte pridáme 2 privátne konštanty, jedna udáva veľkosť vykreslovaného sedadla v pixeloch a druhá medzeru medzi sedadlami v pixeloch. Zvyknite si konštanty používať, až budete chcieť sedadlá zväčšiť, stačí len prepísať jednu konštantu a nemusíte lúštiť vykresľovací kód.
private static final int VELIKOST = 16; private static final int MEZERA = 2;
Môžeme prejsť k metódam.
Vykreslenie
Kinosála by sa mal vedieť vykresliť. Už sme si spomenuli, že budeme kresliť na plátno. Toto plátno typu Graphics a necháme si ho prísť v parametri metódy vykresli (). Na plátno sa potom kreslí pomocou jeho metód. Nás bude zatiaľ zaujímať len metóda fillRect (), ktorá vykreslí obdĺžnik, vyplnený určitou farbou. Metód je tam obrovská kopa pre rôzne geometrické tvary, či už vyplnené alebo nevyplnené. Môžete si ich prejsť, niektoré si vyskúšame ešte v ďalších lekciách.
Pomocou dvoch vnorených cyklov prejdeme všetky sedadlá v poli a na plátno vykreslíme buď zelený alebo červený štvorec. Vonkajším cyklom budeme prechádzať riadky, vnútorným stĺpce v aktuálnom riadku. Farbu určíme podľa toho, či je sedadlo na dané súradnici true alebo false. Kód metódy bude nasledujúci:
public void vykresli(Graphics g) { for (int j = 0; j < sedadla[0].length; j++) { for (int i = 0; i < sedadla.length; i++) { if (sedadla[i][j]) g.setColor(Color.RED); else g.setColor(Color.GREEN); g.fillRect(i * (VELIKOST + MEZERA), j * (VELIKOST + MEZERA), VELIKOST, VELIKOST); } } }
Všimnite si, že v cykloch nepoužívame hodnoty 30 a 15, ale používame sedadla.length a sedadlá [0] .length. Prvý výraz je šírka poľa (počet stĺpcov), druhý je jeho výška (počet riadkov). (Samozrejme záleží na nás, ktorú dimenziu si určíme ako výšku a ktorú ako šírku). Pevnú veľkosť neuvádzame pochopiteľne z dôvodu, že v budúcnosti môžeme pole zväčšiť / zmenšiť a museli by sme v kóde hľadať kde všade sme hodnoty 30 a 15 použili. Týmto problémom je vždy lepšie sa vyhnúť a pracovať s dĺžkou poľa.
Za zmienku stojí aj samotné vykreslenie. Farbu nastavíme metódou setColor (), ktorá berie v parametri jednu z konštánt na triede Color. Čo sa týka metódy fillRect (), jej parametre sú súradnice ľavého horného rohu obdĺžnika a ďalej jeho výška a šírka. Keďže je každé sedadlo široké 16 pixelov + 2 pixely medzera, musíme jeho súradnicu za večnými hodnotou prenásobiť. Pokiaľ je v i napr. Hodnota 2 (kreslíme teda 3. stĺpec), kreslíme na X súradnicu 36, nie na 2 To isté platí pre súradnicu Y.
Neskôr si môžete skúsiť nahradiť fillRect () metódou fillOval (). Funguje úplne rovnako, ale vykreslní elipsu. Určite si po dokončení aplikácie skúste vykresliť aj ďalšie tvary.
Plátno
Ako plátno sme v našej aplikácii použili JPanel. Ten sa však samozrejme vykreslí ako panel, nie ako sedadlá kinosály Aby sme toto správanie zmenili, musíme JPanel zdediť a prepísať jeho metódu paintComponent () tak, aby namiesto toho kreslila kinosála.
Do projektu teda pridáme ešte triedu Platno. Jej obsah bude nasledujúce:
public class Platno extends JPanel { private Kinosal kinosal; public Platno(Kinosal kinosal) { super(); this.kinosal = kinosal; } @Override public void paintComponent(Graphics g) { super.paintComponent(g); kinosal.vykresli(g); } }
Do triedy si v konstruktoru uložíme inštancii kinosály. Následne prepíšeme metódu paintComponent () tak, aby vykreslovala kinosála.
Pozn .: Okrem metódy paintComponent () má komponent aj metódu paint (), ktorú môžeme tiež prepísať a dosiahnem rovnaký výsledok. Je to minimálne trochu mätúce. Podľa manuálov by sme mali správne prepisovať paintComponent (), keďže je to metóda swing, paint () je z AWT.
Prepojenie formuláre s logickou vrstvou
Základ logiky máme hotový, poďme ju prepojiť s formulárom. Prejdeme do kódu formulára a v triede vytvoríme privátnej inštanciu kinosály:
private Kinosal kinosal = new Kinosal();
Teraz je potrebné NetBeans oznámiť, že ten JPanel, ktorý sme na formulár natiahli, nemá byť typu JPanel, ale má to byť naša upravené Platno. JPanel označíme a v Properties oknu sa presunieme na záložku Code. Do vlastnosti Custom Creation Code vložíme nasledujúcu hodnotu:
new Platno(kinosal);
Tým upravíme vytvárajúci kód pre tento panel, ktorý NetBeans generuje a vyzeral by inak takto:
new JPanel();
Udalosť paintComponent () volá systém vo chvíli, kedy sa má okno prekresliť. To je samozrejme v prípade spustenia aplikácie, ale aj po obnovení z minimalizácie, vo chvíli, kedy po okne aplikácie prejdeme iným oknom a podobne.
Keď aplikáciu spustíme, upravený panel sa naozaj vykresľuje ako sedadlá v kine:
Panel je stále typu JPanel, keby sme na ňom chceli volať niektoré špecifické metódy, museli by sme ho pretypovať. V našom prípade to potrebovať nebudeme.
V budúcom dieli si ukážeme, ako kliknutím na určité sedadlo zmeniť jeho stav a sprevádzkujeme tiež ukladanie. Projekt máte ako vždy k stiahnutiu v prílohe pre prípad, že sa vám niečo nepodarilo.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 456x (18.43 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java