Първи стъпки с Java 2D

API 2D на Java е основен API на платформата Java 1.2 (вижте Ресурси за разнообразна информация за API и неговите реализации). Внедряванията на API са налични като част от Java Foundation Classes (JFC) в текущите бета версии на Sun JDK за Windows NT / 95 и Solaris. Тъй като Java 1.2 е финализирана, Java 2D трябва да стане достъпна на повече платформи.

Имайте предвид, че въпреки че Java 2D е разработен донякъде независимо от останалите части на JFC, той все пак е основна част от 1.2 AWT. Ще направим разликата и ще посочим специфични за 2D характеристики за дискусия, но не забравяйте, че тази функционалност е също толкова важна за 1.2 графики, колкото старата поддръжка на 1.0 и 1.1 AWT.

Java 2D разширява предишните AWT механизми за рисуване на 2D графики, манипулиране на текст и шрифтове, зареждане и използване на изображения и дефиниране и работа с цветове и цветови пространства. Ще проучим тези нови механизми в тази и бъдещите колони.

Бележка за номенклатурата и конвенциите

За тази колона основната ми платформа за разработка ще бъде компютър с Windows 95 или Windows NT. Надявам се да предоставя други специфични за платформата съвети и трикове, когато е възможно, но ще се съсредоточа върху Windows, тъй като там ще прекарвам по-голямата част от времето си.

Когато пиша име на метод, то винаги трябва да е във формата methodname(). Последващите скоби имат за цел да отделят това като метод. Методът може или не може да взема параметри. На практика контекстът винаги трябва да изяснява това.

Списъкът с изходния код ще бъде даден с включени номера на редове. Смятам да използвам номерата на редовете за препратка към текста на статията и кодовите списъци, както е подходящо. Това също би улеснило коментирането на колоната, ако сте избрали да отпечатате копие. Моля, имайте предвид обаче, че изходните файлове, свързани с колоната, ще бъдат обикновени * .java файлове (без номера на редове), за да можете да ги изтегляте и развивате с тях.

Тъй като през следващите месеци ще пиша за много от API за медии и комуникации, искам да се уверя, че целият примерен код има смисъл като цяло, както и в отделните му части. Ще се опитам последователно да назовавам моите примери и да ги поставя в сензитивни пакети.

Най-горната част на моята йерархия на пакета ще бъде:

com.javaworld.media 

Всеки API или тема, за които пиша, ще има поне един подпакет под това най-високо ниво. Например целият код за тази 2D статия в Java ще бъде в:

com.javaworld.media.j2d 

Така че, за да извикате първото примерно приложение на Java 2D, трябва да изтеглите кода, да го поставите в своя път на класа, след което да използвате:

java com.javaworld.media.j2d.Пример01 

(Ако пространството от имена е твърде дълго, за да ви хареса или по някаква друга причина искате да използвате примерния код, без да се налага да използвате напълно квалифицираното име, просто коментирайте реда на пакета в началото на всеки файл с изходен код.)

Ще генерирам файл на Java Archive (jar) за примерния код на всяка статия и файловете на класа. Този архив ще бъде достъпен в Ресурсите на всяка колона, ако желаете да го изтеглите и изпълните примерите от архива.

Също така ще запазя актуален файл с jar, съдържащ целия код и класове от текущите и предишните ми колони за програмиране на медии . Този всеобхватен jar файл ще бъде достъпен на моя личен уеб сайт.

Една последна точка върху примерите: Избрах да направя всеки пример, освен ако не отбележа специално, самостоятелно приложение или аплет. Това ще доведе до повтаряне на код от време на време, но според мен най-добре запазва целостта на всеки отделен пример.

Стига за конвенциите. Нека започнем да програмираме с Java 2D!

Graphics2D: По-добър графичен клас

Централният клас в Java 2D API е java.awt.Graphics2Dабстрактният клас, който подкласове java.awt.Graphicsза разширяване на 2D функционалността на изобразяване. Graphics2Dдобавя по-еднаква поддръжка за манипулации с различни форми, като всъщност прави текста, линиите и всякакви други двуизмерни форми сравними по своите възможности и полезност.

Нека започнем с прост пример, показващ как получавате и използвате Graphics2dреференция.

001 пакет com.javaworld.media.j2d; 002 003 импортиране на java.awt. *; 004 импортиране на java.awt.event. *; 005 006 публичен клас Example01 разширява Frame {007 / ** 008 * Инстанцира обект Example01. 009 ** / 010 публична статична void main (String args []) {011 new Example01 (); 012} 013 014 / ** 015 * Нашият конструктор Example01 задава размера на рамката, добавя визуалните компоненти 016 * и след това ги прави видими за потребителя. 017 * Той използва клас адаптер, за да се справи с потребителя, затварящ 018 * рамката. 019 ** / 020 public Пример01 () {021 // Заглавието на нашата рамка. 022 супер ("Java 2D Пример01"); 023 024 // Задайте размера на рамката. 025 setSize (400 300); 026 027 // Трябва да включим видимостта на нашата рамка 028 //, като зададем параметъра Visible на true. 029 setVisible (вярно); 030 031 // сега,искаме да сме сигурни, че правилно разполагаме с ресурси 032 // тази рамка използва, когато прозорецът е затворен. За това използваме 033 // анонимен адаптер за вътрешен клас. 034 addWindowListener (new WindowAdapter () 035 {public void windowClosing (WindowEvent e) 036 {dispose (); System.exit (0);} 037} 038); 039} 040 041 / ** 042 * Методът на боя осигурява истинската магия. Тук ние 043 * прехвърляме Graphics обекта на Graphics2D, за да илюстрираме 044 *, че можем да използваме същите стари графични възможности с 045 * Graphics2D, които сме свикнали да използваме с Graphics. 046 ** / 047 публична боя за празнота (Графика g) {048 // Ето как използвахме да нарисуваме квадрат с ширина 049 // от 200, височина 200 и започвайки от x = 50, y = 50. 050 g.setColor (Color.red); 051 г. DrawRect (50 50 200 200); 052 053 // Некаs задайте цвета на син цвят и след това използвайте обекта Graphics2D 054 //, за да нарисувате правоъгълник, изместен от квадрата. 055 // Досега не сме направили нищо с помощта на Graphics2D, което 056 // не можем да направим и с помощта на Graphics. (Ние всъщност сме 057 // използваме Graphics2D методи, наследени от Graphics.) 058 Graphics2D g2d = (Graphics2D) g; 059 g2d.setColor (Color.blue); 060 g2d.drawRect (75,75,300,200); 061} 062}

Когато изпълнявате Example01, трябва да видите червен квадрат и син правоъгълник, както е показано на фигурата по-долу. Имайте предвид, че има известен проблем с производителността на версията на Windows NT / 95 на JDK 1.2 Beta 3 (най-актуалната версия 1.2 от тази колона). Ако този пример е болезнено бавен във вашата система, може да се наложи да заобиколите грешката, както е документирано в JavaWorld Java Tip 55 (вижте Ресурси по-долу за този съвет).

Обърнете внимание, че както не правите екземпляр директно на Graphicsобект, така и вие не създавате екземпляр на Graphics2Dобект. По-скоро изпълнението на Java конструира обект за рендиране и го предава paint()(ред 047 в списъка с кодове Example01), а на платформи Java 1.2 и по-нататък този обект реализира и Graphics2Dабстрактния клас.

Досега не сме направили нещо особено специално с нашите 2D графични възможности. Нека добавим малко код в края на paint()метода на нашия предишен пример и въведем няколко функции, нови за Java 2D (Пример 02):

001 / ** 002 * Тук използваме нови функции на Java 2D API като affine 003 * преобразувания и Shape обекти (в този случай общ 004 *, GeneralPath). 005 ** / 006 публична боя за празнота (графика g) {007 g.setColor (Color.red); 008 g.rawRect (50,50,200,200); 009 010 Graphics2D g2d = (Graphics2D) g; 011 g2d.setColor (Color.blue); 012 g2d.drawRect (75,75,300,200); 013 014 // Сега, нека нарисуваме друг правоъгълник, но този път, нека 015 // използваме GeneralPath, за да го зададем сегмент по сегмент. 016 // Освен това ще преведем и завъртим този правоъгълник 017 // спрямо пространството на устройствата (и по този начин към 018 // първите два четириъгълника), използвайки AffineTransform. 019 // Ние също ще сменим цвета му. 020 GeneralPath path = new 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 (пътека); 035}

Имайте предвид, че тъй като GeneralPathсе намира в java.awt.geomпакета, трябва да сме сигурни, че добавяме и линия за импортиране:

импортиране на java.awt.geom. *; 

Резултатът от пример 02 е показан на следващата фигура.

Java 2D дава възможност за спецификация на произволни форми с помощта на java.awt.Shapeинтерфейса. Различни форми по подразбиране като правоъгълници, полигони, 2D линии и др., Изпълняват този интерфейс. Един от най-интересните от тях по отношение на гъвкавостта е java.awt.geom.GeneralPath.

GeneralPaths ви позволяват да опишете път с произволен брой ръбове и потенциално изключително сложна форма. В пример 02 създадохме правоъгълник (линии 020-025), но също толкова лесно бихме могли да добавим друга страна или страни, за да направим петоъгълник, седмоъгълник или друг многостранен многоъгълник. Също така имайте предвид, че за разлика от стандартния Graphicsкод, Java 2D ни позволява да задаваме координати, като използваме числа с плаваща запетая вместо цели числа. CAD продавачи по света, радвайте се! В действителност, Java 2D подкрепя integer, doubleи floatingаритметиката на много места.

Вероятно сте забелязали също така, че когато създадохме пътя, предадохме параметър GeneralPath.EVEN_ODD, в конструктора (ред 020). Този параметър представлява правило за навиване, което казва на визуализатора как да определи вътрешността на формата, посочена от нашия път. Моля, вижте документацията за Java 2D javadoc, посочена в Ресурсите, за повече информация относно правилата за навиване на Java 2D.

Другата голяма иновация в Example02 се върти около използването на java.awt.geom.AffineTransforms (редове 027-031). Ще оставя спецификата на такива трансформи на читателя (вижте Ресурси за статии, които обсъждат това по-подробно), но е достатъчно да се каже, че AffineTransformви позволява да оперирате всяка Java 2D графика, за да я преведете (преместите), завъртите , мащабирайте го, срязвайте го или изпълнявайте комбинации от тези манипулации.

The key to AffineTransform lies in the concept of Device Space and User Space. Device Space is that area into which the graphics will be rendered on the screen. This is analogous to the coordinates that are used when one creates regular AWT-style Graphics-based 2D graphics. User Space, however, is a translatable, rotatable coordinate system that may be operated on by one or more AffineTransforms.

Device Space and User Space coordinate systems initially overlap, with the origin at the upper left of the rendering surface (here, a Frame). The positive x axis moves right from the origin, while the positive y axis moves down.

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.

. в компютърната графика.) GeneralPathМетодите, които чертаят всяка от тези криви, са:

  • lineTo() за прави сегменти (посочете само крайни точки)
  • quadTo() за квадратни криви (посочете една контролна точка)
  • curveTo() за трето подредени криви (посочете две контролни точки, изчертани с помощта на кубична крива на Безие)