Početak rada s Javom 2D

Java 2D API osnovni je API platforme Java 1.2 (pogledajte Resurse za razne informacije o API-ju i njegovim implementacijama). Implementacije API-ja dostupne su kao dio Java Foundation Classes (JFC) u trenutnim beta izdanjima Sun JDK za Windows NT / 95 i Solaris. Kako je Java 1.2 finalizirana, Java 2D trebao bi postati dostupan na više platformi.

Imajte na umu da je, iako je Java 2D razvijen donekle neovisno od ostalih dijelova JFC-a, ipak ključni dio 1.2 AWT-a. Razlikovat ćemo razliku i istaknuti 2D-specifične značajke za raspravu, ali trebate imati na umu da je ova funkcionalnost jednako važna za 1.2 grafiku kao i stara 1.0 i 1.1 AWT podrška.

Java 2D proširuje prethodne AWT mehanizme za crtanje 2D grafike, manipuliranje tekstom i fontovima, učitavanje i korištenje slika te definiranje boja i prostora boja i bavljenje njima. Istražit ćemo te nove mehanizme u ovoj i budućim kolumnama.

Bilješka o nomenklaturi i konvencijama

U ovom će stupcu moja primarna razvojna platforma biti računalo sa sustavom Windows 95 ili Windows NT. Nadam se da ću pružiti i druge savjete i trikove specifične za platformu, ali usredotočit ću se na Windows jer ću tamo provoditi većinu svog vremena.

Kad napišem naziv metode, to bi uvijek trebalo biti oblika methodname(). Zagrade u završnici trebaju ovo razdvojiti kao metodu. Metoda može ili ne mora uzimati parametre. U praksi kontekst to uvijek treba jasno objasniti.

Dat će se popisi izvornih kodova s ​​uključenim brojevima linija. Planiram upotrijebiti brojeve redaka za ukrštanje teksta članka i popisa kodova prema potrebi. To bi vam također trebalo olakšati bilježenje stupca ako odlučite ispisati kopiju. Međutim, imajte na umu da će izvorne datoteke povezane sa stupcem biti redovite * .java datoteke (bez brojeva redaka) kako biste ih mogli preuzimati i razvijati s njima.

Budući da ću o sljedećim mjesecima pisati o mnogim API-ima za medije i komunikaciju, želim biti siguran da sav uzorak koda ima smisla u cjelini, kao i u pojedinim dijelovima. Pokušat ću dosljedno imenovati svoje primjere i smjestiti ih u senzibilne pakete.

Vrh moje hijerarhije paketa bit će:

com.javaworld.media 

Svaki API ili tema o kojoj pišem imat će barem jedan podpaket ispod ove najviše razine. Na primjer, sav kôd za ovaj 2D članak u Javi bit će u:

com.javaworld.media.j2d 

Dakle, da biste pozvali prvi primjer aplikacije na Javi 2D, preuzeli biste kôd, stavili ga u put predavanja, a zatim upotrijebili:

java com.javaworld.media.j2d.Primjer01 

(Ako je prostor imena predugačak po vašem ukusu ili iz nekog drugog razloga želite koristiti primjer koda, a da ne morate koristiti potpuno kvalificirano ime, jednostavno komentirajte redak paketa na početku svake datoteke izvornog koda.)

Generirat ću datoteku Java Archive (jar) za primjere koda i datoteka klase svakog članka. Ova će arhiva biti dostupna u resursima svakog stupca, ako je želite preuzeti i izvršiti primjere iz arhive.

Također ću čuvati ažurnu jar datoteku koja sadrži sav kôd i klase iz mojih trenutnih i prethodnih stupaca Programiranje medija . Ova sveobuhvatna jar datoteka bit će dostupna na mojem osobnom web mjestu.

Posljednja stvar na primjerima: Odlučio sam napraviti svaki primjer, osim ako nisam posebno napomenuo, samostalnu aplikaciju ili aplet. To će s vremena na vrijeme dovesti do ponavljanja koda, ali smatram da najbolje čuva cjelovitost svakog pojedinačnog primjera.

Dosta o konvencijama. Krenimo s programiranjem s Javom 2D!

Graphics2D: Bolja klasa grafike

Središnja klasa u Java 2D API-ju je java.awt.Graphics2Dapstraktna klasa koja potklasa java.awt.Graphicsproširuje funkcionalnost 2D prikazivanja. Graphics2Ddodaje ujednačeniju podršku za manipulacije raznim oblicima, što zapravo čini tekst, crte i sve vrste drugih dvodimenzionalnih oblika usporedivim po svojim mogućnostima i korisnosti.

Počnimo s jednostavnim primjerom koji pokazuje kako dobivate i koristite Graphics2dreferencu.

001 paket com.javaworld.media.j2d; 002 003 import java.awt. *; 004 import java.awt.event. *; 005 006 javna klasa Example01 proširuje okvir {007 / ** 008 * Instancira objekt Example01. 009 ** / 010 javna statička void glavna (String args []) {011 new Example01 (); 012} 013 014 / ** 015 * Naš konstruktor Example01 postavlja veličinu okvira, dodaje vizualne komponente 016 *, a zatim ih čini vidljivima korisniku. 017 * Koristi klasu adaptera za rješavanje problema s korisnikom koji zatvara 018 * okvir. 019 ** / 020 public Example01 () {021 // Naslov našeg okvira. 022 super ("Java 2D Primjer01"); 023 024 // Postavite veličinu okvira. 025 setSize (400.300); 026 027 // Moramo uključiti vidljivost našeg okvira 028 // postavljanjem parametra Visible na true. 029 setVisible (true); 030 031 // sada,želimo biti sigurni da pravilno raspolažemo resursima 032 // ovaj okvir koristi kada je prozor zatvoren. Za to koristimo 033 // anonimni adapter unutarnje klase. 034 addWindowListener (novi WindowAdapter () 035 {public void windowClosing (WindowEvent e) 036 {dispose (); System.exit (0);} 037} 038); 039} 040 041 / ** 042 * Metoda boje pruža pravu čaroliju. Ovdje smo 043 * prebacili grafički objekt na Graphics2D da bismo ilustrirali 044 * da možemo koristiti iste stare grafičke mogućnosti s 045 * Graphics2D koje smo navikli koristiti s Graphics. 046 ** / 047 javna boja za praznine (grafika g) {048 // Evo kako smo crtali kvadrat širine 049 // od 200, visine od 200 i počevši od x = 50, y = 50. 050 g.setColor (boja.crvena); 051 g.drawRect (50,50,200,200); 052 053 // Neka 's postavite Boju na plavu, a zatim pomoću Graphics2D 054 // objekta nacrtajte pravokutnik, pomaknut od kvadrata. 055 // Do sada nismo učinili ništa koristeći Graphics2D što 056 // nismo mogli učiniti ni pomoću Graphics. (Mi zapravo 057 // koristimo Graphics2D metode naslijeđene od Graphics.) 058 Graphics2D g2d = (Graphics2D) g; 059 g2d.setColor (Color.blue); 060 g2d.drawRect (75,75.300.200); 061} 062}

Kada izvršavate Example01, trebali biste vidjeti crveni kvadrat i plavi pravokutnik, kao što je prikazano na donjoj slici. Imajte na umu da je poznat problem s performansama verzije JDK 1.2 Beta 3 za Windows NT / 95 (najnovije izdanje 1.2 iz ovog stupca). Ako je ovaj primjer bolno spor na vašem sustavu, možda ćete trebati zaobići programsku pogrešku kako je dokumentirano u JavaWorld Java Tip 55 (za ovaj savjet pogledajte Resurse u nastavku).

Imajte na umu da kao što Graphicsobjekt ne instancirate izravno, tako ni objekt ne instantirate Graphics2D. Umjesto toga, Java runtime konstruira objekt prikazivanja i prosljeđuje ga paint()(redak 047 u popisu kodova Example01), a na Java 1.2 platformama i šire ovaj objekt implementira i Graphics2Dapstraktnu klasu.

Do sada nismo učinili ništa posebno s našim 2D grafičkim mogućnostima. Dodajmo malo koda na kraj paint()metode našeg prethodnog primjera i uvedimo nekoliko značajki novih u Java 2D (Primjer 02):

001 / ** 002 * Ovdje koristimo nove značajke Java 2D API-ja kao što su affine 003 * transformacije i Shape objekti (u ovom slučaju generički 004 *, GeneralPath). 005 ** / 006 boja za javne praznine (grafika g) {007 g.setColor (boja.crvena); 008 g.drawRect (50,50,200,200); 009 010 Graphics2D g2d = (Graphics2D) g; 011 g2d.setColor (Color.blue); 012 g2d.drawRect (75,75,300,200); 013 014 // Sada, nacrtajmo još jedan pravokutnik, ali ovaj put, hajde da 015 // upotrijebimo GeneralPath da ga odredimo segment po segment. 016 // Nadalje, prevest ćemo i rotirati ovaj pravokutnik 017 // u odnosu na Prostor uređaja (a time i na 018 // prva dva četverokuta) koristeći AffineTransform. 019 // Također ćemo promijeniti njegovu boju. 020 GeneralPath path = novi GeneralPath (GeneralPath.EVEN_ODD); 021 path.moveTo (0.0f, 0.0f); 022 path.lineTo (0.0f, 125.0f); 023 path.lineTo (225.0f, 125.0f);024 path.lineTo (225.0f, 0.0f); 025 path.closePath (); 026 027 AffineTransform at = new AffineTransform (); 028 at.setToRotation (-Math.PI / 8.0); 029 g2d.transform (at); 030 at.setToTranslation (50.0f, 200.0f); 031 g2d.transform (at); 032 033 g2d.setColor (Color.green); 034 g2d.fill (put); 035}

Imajte na umu da, budući da GeneralPathse nalazi u java.awt.geompaketu, moramo biti sigurni da smo dodali i liniju za uvoz:

import java.awt.geom. *; 

Izlaz iz Primjera 02 prikazan je na sljedećoj slici.

Java 2D omogućuje specificiranje proizvoljnih oblika pomoću java.awt.Shapesučelja. Različiti zadani oblici poput pravokutnika, poligona, 2D linija itd. Implementiraju ovo sučelje. Jedan od najzanimljivijih među njima u smislu fleksibilnosti je java.awt.geom.GeneralPath.

GeneralPathOmogućuju vam opis staze s proizvoljnim brojem bridova i potencijalno izuzetno složenim oblikom. U Primjeru 02 stvorili smo pravokutnik (linije 020-025), ali jednako smo lako mogli dodati još jednu stranu ili stranice da napravimo peterokut, sedmerokut ili neki drugi višestrani poligon. Također imajte na umu da za razliku od standardnog Graphicskoda, Java 2D omogućuje nam da odredimo koordinate pomoću brojeva s pomičnom zarezom umjesto cijelih brojeva. CAD dobavljači svijeta, radujte se! U stvari, Java 2D podržava integer, doublei floatingaritmetika u mnogim mjestima.

Vjerojatno ste također primijetili da kada smo kreirali putanju proslijedili smo parametar GeneralPath.EVEN_ODD, u konstruktor (redak 020). Ovaj parametar predstavlja pravilo namotavanja koje govori prikazivaču kako odrediti unutrašnjost oblika navedenog našom stazom. Više informacija o pravilima navijanja Java 2D potražite u dokumentaciji Java 2D javadoc koja je navedena u Resursima.

Druga glavna inovacija u Primjeru 02 vrti se oko upotrebe java.awt.geom.AffineTransforms (linije 027-031). Specifičnosti takvih transformacija prepustit ću čitatelju (pogledajte Resurse za članke koji o tome detaljnije raspravljaju), ali dovoljno je reći da AffineTransformvam omogućuju rad na bilo kojoj Java 2D grafici da biste je preveli (premjestili), rotirali , skalirajte ga, posijecite ili izvodite kombinacije ovih manipulacija.

Ključ AffineTransformleži u konceptu prostora uređaja i korisničkog prostora . Prostor uređaja je ono područje u koje će se grafika prikazivati ​​na zaslonu. To je analogno koordinatama koje se koriste kada se stvaraju redovite Graphics2D grafike u stilu AWT . Korisnički prostor, međutim, prevodivi je, rotacijski koordinatni sustav kojim može upravljati jedan ili više AffineTransforms.

Prostor uređaja i koordinatni prostor korisničkog prostora u početku se preklapaju, s ishodištem u gornjem lijevom kutu površine prikazivanja (ovdje okvir). Pozitivna os x pomiče se desno od ishodišta, dok se pozitivna os y pomiče prema dolje.

After the first transformation in Example02 (lines 028 and 029), the User Space coordinate system has been rotated 22.5 degrees counterclockwise relative to the Device Space. Both still share the same origin. (Note that rotations are specified in radians, with -PI/8 radians equaling -22.5 degrees, or 22.5 degrees CCW.) If we were to stop here and draw the rectangle, it would be rotated mostly out of our field of view in the application Frame.

We next apply a second transformation (lines 030 and 031), this one a translation, after the rotation is complete. This moves the User Space coordinate system relative to the Device Space, shifting it down 200.0 (float) units and right 50.0 (float) units.

When we fill in the green rectangle, it is translated and rotated relative to the Device Space.

Of Bezier and higher-ordered curves

Now that we have examined how transforms can be used to manipulate graphical objects, let's reexamine how we build complex and interesting arbitrary shapes.

Curves are used throughout mathematics and computer graphics to approximate complex shapes using a finite, well-defined (and ideally small) number of mathematical points. Whereas the standard AWT did not directly support drawing with arbitrary curves in the past (Java 1.0 or 1.1 platforms), Java 2D adds built-in support for first-, second-, and third-order curves. You can draw curves with two end points and zero, one, or two control points. Java 2D computes first- and second-order curves using linear and quadratic formulas and cubic, or third-order, curves using Bezier curves.

(Bezierove krivulje su vrsta parametarskih polinomskih krivulja koje imaju neka vrlo poželjna svojstva vezana uz izračunavanje zatvorenih krivulja i površina. Koriste se u brojnim grafičkim aplikacijama. Pogledajte Resurse za više informacija o uporabi parametarskih polinoma i Bezierove krivulje u računalnoj grafici.) GeneralPathMetode koje crtaju svaku od ovih krivulja su:

  • lineTo() za ravne segmente (navesti samo krajnje točke)
  • quadTo() za kvadratne krivulje (navesti jednu kontrolnu točku)
  • curveTo() za treće poredane krivulje (navedite dvije kontrolne točke, nacrtane pomoću kubične Bezierove krivulje)