07 Java2d
07 Java2d
Canned goods always limit you to what the manufacturer believes you will need AWT did a reasonable job at portable graphics JFC/Swing improved this with a better look and feel as well as a more components Is there anything else we might want to do?
Demonstration/presentation software
Powerpoint Interactive product tours
Destinations include
Window (viewport) on screen Full screen (J2SE 1.4 and later) Image buffer Printer (physical printing device)
Graphic Context
Seven Aspects
Font Composite (intersections) Transform (displacement, scale) Stroke (pen size) Paint (fill color / pattern) Hints (performance / quality tradeoffs Clip (drawing extents)
Of course, we'll use JFC/Swing for this You need to import javax.swing.* and java.awt.*
Every Swing object inherits from JComponent JComponent has a few methods that can be overridden in order to draw special things
Which JComponent
This method is called whenever the system needs to draw the component If this were AWT, we would override this method and put our drawing routines here Generally, we don't override this in Swing
paintComponent(Graphics g)
We then create our custom rendering method somewhere else in the class or in a separate class
Rendering to a Window
public class SimpleJ2D extends javax.swing.JPanel { public void paintComponent(java.awt.Graphics g) { java.awt.Graphics2D g2 =(java.awt.Graphics2D)g; SimpleRenderer.render(g2); } public static void main(String[] args) { SimpleJ2D SJ2D = new SimpleJ2D(); javax.swing.JFrame f = new javax.swing.JFrame(); f.getContentPane().add(SJ2D); f.setSize(640,480); f.show(); } }
Suggestion:
Create interface Renderer (single method render) Define rendering logic in an implementation of the interface Renderer Output device classes use implementations of Renderer
Rendering to a Printer
public class PrinterRendering implements Printable { public int print(Graphics g, PageFormat f, int pageIndex) { Renderer.paint(g); } public static void main(String[] args) { PrinterJob printerJob = PrinterJob.getPrinterJob(); PageFormat pageFormat = printerJob.defaultPage(); if (printerJob.printDialog() { printerJob.print(); } else { System.out.println("Print job cancelled"); } } }
Rendering to an Image
BufferedImage bi = new BufferedImage(xsize, ysize, type); Graphics2D g = bi.createGraphics(); // notice that createGraphics returns a g2d object directly, no cast! Renderer.render(g); // save the image File file = new File("images","test.jpg"); FileOutputStream out = new FileOutputStream(file); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bi); param.setQuality(1.0f, false); encoder.setJPEGEncodeParam(param); encoder.encode(bi);
myRenderer(Graphics g)
First we need to setup our environment We will almost always need to know the size of the screen that we'll be drawing on...
It's good practice to make your drawing routines scalable with the size of the component
Coordinate Systems
User Space
The programmer operates in this space Origin is on the upper left Positive X goes right Positive Y goes down
Device Space
Where the actually drawing takes place Device dependent JAVA2D performs the mapping
10
Affine Transformations
Translation: m02 = tx, m12 = ty Scale: m00 = sx, m11 = sy Shear: m01 = shx, m10 = shy Rotation: m00 = cos(theta), m01 = -sin(theta), m10 = sin(theta), m11 = cos(theta)
11
Transforming Objects
There is a class called AffineTransform You can call things like translate(x,y), rotate(degrees) and skew(x,y) on any instance of AffineTransform You can then use "setTransform" on the g2 object reference to apply your new transform
12
13
Filled Objects
Use the fill method instead of draw to draw filled into objects:
14
15
Compositing Elements
What happens when you overlay one element on top of another element? Complete opacity? Blending of colors?
Clipping Region
Define region where things can drawn successfully Convenient method for making it rectangular Demo of a moving clip:
http://java.sun.com/docs/books/tutorial/2d/display/ClipImage.html
16
Rendering Hints
Keys and Values Alpha interpolation - quality, or speed Antialiasing - on or off Color rendering - quality or speed Dithering - disable or enable Fractional metrics - on or off Interpolation - nearest-neighbor, bilinear, or bicubic Rendering - quality, or speed Text antialiasing - on, or off There is no guarantee these do anything!
The "draw()" method takes as arguments elements that can be instantiated without a name g2.draw(new Line2D.Double(x,y+w-1,x+h,y)); You could also instantiate and keep a list of the objects that you've drawn for later use import java.awt.geom.* for this primitive
17
The setStroke can take options like widestroke or dashed to change the line type or width g2.setStroke(new BasicStroke(width)); There are primitives you can placed into a draw call for all sorts of shapes g2.draw(new Ellipse2D.Double(x, y, w, h));
General Paths
Use the GeneralPath drawing object to create lines of arbitrary configuration You have to make sure that you can describe your path in terms of a quadratic or cubic equation Really complicated paths can be sequences of cubic paths
18
Using Images
java.awt.Image abstract the notion of bitmapped pictures (GIF, JPEG, etc) Call Toolkit.getDefaultToolkit().getImage(url) to retrieve the image Call g2.drawImage(myImg, x, y, this) to draw Lots of built in image processing functionality Look at JAI (Java Advanced Imaging) API for additional functionality
19
Drawing Text
Simple text is very easy: g.setFont("Whatever Font"); g.drawString("Hello World" xpos, ypos); Wrapped text is very hard:
public static void drawString(Graphics2D g, String theText, float initX, float initY, float maxX) { java.text.AttributedString ASmsg = new java.text.AttributedString(theText); java.text.AttributedCharacterIterator paragraph = ASmsg.getIterator(); int paragraphStart = paragraph.getBeginIndex(); int paragraphEnd = paragraph.getEndIndex(); java.awt.font.LineBreakMeasurer lineMeasurer = new java.awt.font.LineBreakMeasurer(paragraph, new java.awt.font.FontRenderContext(null, false, false)); float formatWidth = maxX - initX; float drawPosY = initY; lineMeasurer.setPosition(paragraphStart); while (lineMeasurer.getPosition() lt paragraphEnd) { java.awt.font.TextLayout layout = lineMeasurer.nextLayout(formatWidth); drawPosY += layout.getAscent(); float drawPosX; if (layout.isLeftToRight()) { drawPosX = initX; } else { drawPosX = formatWidth - layout.getAdvance(); } // Draw the TextLayout at (drawPosX, drawPosY). layout.draw(g, drawPosX, drawPosY); } }
20
21
Animation
repaint() is used to schedule the component to be repainted... but sometimes that is not fast enough A simple hack is to override repaint()
This causes heavy CPU usage but gets the results that you would expect because it repaints as fast as possible
22
Animation
Animation Example
import import import import java.awt.*; java.awt.event.*; java.awt.geom.*; javax.swing.*;
public class AnimPanel extends JPanel implements ActionListener { private Timer timer; public AnimPanel() { timer = new Timer(500, this); // half second timer.setInitialDelay(0); timer.setCoalesce(true); timer.start(); } public void paintComponent(Graphics g) { super.paintComponent(g); customDrawingMethod(g); } public void actionPerformed(ActionEvent e) { this.repaint(); }
23
Animation Example
public void customDrawingMethod(Graphics g) { Graphics2D g2 = (Graphics2D) g; double w = (getSize()).getWidth(); double h = (getSize()).getHeight(); double r1 = Math.random(); double r2 = Math.random(); g2.setPaint(Color.blue); g2.fill(new Rectangle2D.Double(r1*w-w/16, r2*h-h/16, w/8, h/8)); } public static void main(String[] args) { JFrame Frame = new JFrame(); (Frame.getContentPane()).add(new AnimPanel()); Frame.setSize(new java.awt.Dimension(600,400)); Frame.show(); } }
Summary
24