Graphical rich components Using the forgotten power of Java Swing Gerrit Grunwald @hansolo_ Donnerstag, 2. Dezember 2010 1 Presentation goals Short overview Explain the layer approach Focus on custom components Show possible workflows Introduce a tool to convert graphics Arouse your interest PAGE: Donnerstag, 2. Dezember 2010 2 2 It`s the 21`st century PAGE: Donnerstag, 2. Dezember 2010 3 3 Everything has to be shiny, fancy, rich... PAGE: Donnerstag, 2. Dezember 2010 4 4 Java is old... PAGE: Donnerstag, 2. Dezember 2010 5 5 It has a lot of ,,new" competitors PAGE: Donnerstag, 2. Dezember 2010 6 6 Silverlight, Flex, JavaFX... PAGE: Donnerstag, 2. Dezember 2010 7 7 Silverlight, Flex, JavaFX... PAGE: Donnerstag, 2. Dezember 2010 8 8 Examples... PAGE: Donnerstag, 2. Dezember 2010 9 9 PAGE: 10 Donnerstag, 2. Dezember 2010 10 So why using Java Swing ? PAGE: 11 Donnerstag, 2. Dezember 2010 11 Why not ?! PAGE: 12 Donnerstag, 2. Dezember 2010 12 More than 800 Million clients PAGE: 13 Donnerstag, 2. Dezember 2010 13 Powerful, stable, fast... PAGE: 14 Donnerstag, 2. Dezember 2010 14 Well known ! PAGE: 15 Donnerstag, 2. Dezember 2010 15 So it makes sense... PAGE: 16 Donnerstag, 2. Dezember 2010 16 But where to start ? PAGE: 17 Donnerstag, 2. Dezember 2010 17 One general approach... PAGE: 18 Donnerstag, 2. Dezember 2010 18 Java Language java Security javac Int'l javadoc RMI apt IDL jar Deploy javap Monitoring JPDA Troubleshoot JConsole Scripting JVM TI Tools & Tool APIs Deployment Technologies Deployment Java Webstart Java Plug-in User Interface Toolkits Integration Libraries AWT Accessibility Drag n Drop Swing Input Methods Image I/O Java 2D Print Service Sound Extending JComponent IDL JDBC JNDI RMI RMI-IIOP Beans Intl Support Override Mechanism Input/Output JMX JNI Networking Security Serialization Extension Mechanism lang and util Collections Concurrency Utilities JAR Logging Management Preferences API Ref Objects Reflection Regular Expressions Versioning Zip Math XML JAXP Other Base Libraries lang and util Base Libraries Instrumentation Java Virtual Machine Platforms Java Hotspot Client VM Java Hotspot Server VM Solaris Linux Windows Other PAGE: 19 Donnerstag, 2. Dezember 2010 19 @Override paintComponent() PAGE: 20 Donnerstag, 2. Dezember 2010 20 But do not pollute paintComponent() PAGE: 21 Donnerstag, 2. Dezember 2010 21 It`s your choice... Active approach: Draw in paintComponent() Passive approach: Draw in BufferedImage Advantages: all painting code is at one place resizing is a no brainer Advantages: faster* less cluttered code Drawbacks: ugly code performance loss* Drawbacks: resizing is more complex distributed painting code * depends on the complexity of the graphics PAGE: 22 Donnerstag, 2. Dezember 2010 22 Try to avoid this protected void paintComponent(Graphics g) { ... RoundRectangle2D shape = new RoundRectangle2D.Double(x, y, w, h, r, r); Point2D start = new Point2D.Double(0, top); Point2D stop = new Point2D.Double(0, bottom); float[] fractions = { 0.0f, 1.0f }; Color[] colors = { new Color(0xFF0000), new Color(0x00FF00) }; LinearGradientPaint gradient = new LinearGradientPaint(start, stop, fractions, colors); ... } PAGE: 23 Donnerstag, 2. Dezember 2010 23 Better use this protected void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g.create(); g2.drawImage(shapeImage, 0, 0, null); ... } private BufferedImage createShapeImage() { ... Graphics2D g2 = image.createGraphics(); RoundRectangle2D shape = new RoundRectangle2D.Double(x, y, w, h, r, r); Point2D start = new Point2D.Double(0, top); Point2D stop = new Point2D.Double(0, bottom); float[] fractions = { 0.0f, 1.0f }; Color[] colors = { new Color(0xFF0000), new Color(0x00FF00) }; LinearGradientPaint gradient = new LinearGradientPaint(start, stop, fractions, colors); ... return image; } PAGE: 24 Donnerstag, 2. Dezember 2010 24 Conclusion... PAGE: 25 Donnerstag, 2. Dezember 2010 25 Put static painting code in a BufferedImage PAGE: 26 Donnerstag, 2. Dezember 2010 26 So how to proceed ? PAGE: 27 Donnerstag, 2. Dezember 2010 27 We need 2 things A component template Painting code PAGE: 28 Donnerstag, 2. Dezember 2010 28 The component template A class derived from javax.swing.JComponent Implementation of java.awt.event.ComponentListener A value property with it`s get and set method Three buffered images (background, value and foreground) A init method to initalize the images A little bit of resizing logic Override paintComponent() method Three methods that create the images PAGE: 29 Donnerstag, 2. Dezember 2010 29 The painting code Means extensive use of the Java2D API... PAGE: 30 Donnerstag, 2. Dezember 2010 30 The painting code Means extensive use of the Java2D API... The Java 2D Application Programming Interface (API) provides a powerful, flexible framework for using device- and resolution-independent graphics in Java programs. The Java 2D API extends the graphics and imaging classes defined by java.awt, while maintaining compatibility for existing programs. The Java 2D API enables developers to easily incorporate high-quality 2D graphics, text, and images in Java applications and applets. taken from the Java2D API whitepaper PAGE: 30 Donnerstag, 2. Dezember 2010 30 Example please... PAGE: 31 Donnerstag, 2. Dezember 2010 31 A simple gauge Analyze the image and you`ll figure out... PAGE: 32 Donnerstag, 2. Dezember 2010 32 A simple gauge Analyze the image and you`ll figure out... Most of the gauge is static Only the pointer is dynamic PAGE: 32 Donnerstag, 2. Dezember 2010 32 The layer approach... PAGE: 33 Donnerstag, 2. Dezember 2010 33 E.g. a simple button Text PAGE: 34 Donnerstag, 2. Dezember 2010 34 Layered it looks like this... Frame Background Foreground Content Text PAGE: 35 Donnerstag, 2. Dezember 2010 35 Back to our gauge PAGE: 36 Donnerstag, 2. Dezember 2010 36 Back to our gauge - The background PAGE: 36 Donnerstag, 2. Dezember 2010 36 Back to our gauge - The background PAGE: 36 Donnerstag, 2. Dezember 2010 36 Back to our gauge - The background PAGE: 36 Donnerstag, 2. Dezember 2010 36 Back to our gauge - The background PAGE: 36 Donnerstag, 2. Dezember 2010 36 Back to our gauge - The background PAGE: 36 Donnerstag, 2. Dezember 2010 36 Back to our gauge - The background PAGE: 36 Donnerstag, 2. Dezember 2010 36 Back to our gauge - The background PAGE: 36 Donnerstag, 2. Dezember 2010 36 Back to our gauge - The background PAGE: 36 Donnerstag, 2. Dezember 2010 36 Back to our gauge - The background PAGE: 36 Donnerstag, 2. Dezember 2010 36 Back to our gauge - The background PAGE: 36 Donnerstag, 2. Dezember 2010 36 Back to our gauge - The background - The content PAGE: 36 Donnerstag, 2. Dezember 2010 36 Back to our gauge - The background - The content - The pointer PAGE: 36 Donnerstag, 2. Dezember 2010 36 Back to our gauge - The background - The content - The pointer PAGE: 36 Donnerstag, 2. Dezember 2010 36 Back to our gauge - The background - The content - The pointer PAGE: 36 Donnerstag, 2. Dezember 2010 36 DEMO Click to open youTube video Fireworks Demo - creating the gauge background and than switch to the already created stuff PAGE: 37 Donnerstag, 2. Dezember 2010 37 Original Copy PAGE: 38 Donnerstag, 2. Dezember 2010 38 Ok but how to do this in Java ? PAGE: 39 Donnerstag, 2. Dezember 2010 39 The solution... PAGE: 40 Donnerstag, 2. Dezember 2010 40 Conversion... PAGE: 41 Donnerstag, 2. Dezember 2010 41 The hard way PAGE: 42 Donnerstag, 2. Dezember 2010 42 E.g. the background ellipse PAGE: 43 Donnerstag, 2. Dezember 2010 43 Create the ellipse... Ellipse2D bckg = new Ellipse2D.Double(0,0,404,404); 0,0 404,404 PAGE: 44 Donnerstag, 2. Dezember 2010 44 Pick the positions... Point2D start = new Point2D.Double(117, 20); Point2D stop = new Point2D.Double(259, 395); start stop PAGE: 45 Donnerstag, 2. Dezember 2010 45 Guess the fractions... float[] fractions = { 0.0f, 0.1f, 0.25f, 0.45f, 0.75f, 1.0f }; PAGE: 46 Donnerstag, 2. Dezember 2010 46 Grab the colors... Color[] { new new new new new new }; colors = Color(189,191,190,255), Color(243,243,243,255), Color(243,243,243,255), Color(120,116,104,255), Color(129,130,122,255), Color(76,76,74,255) PAGE: 47 Donnerstag, 2. Dezember 2010 47 Create the gradient... LinearGradientPaint gradient = new LinearGradientPaint(start, stop, fractions, colors); PAGE: 48 Donnerstag, 2. Dezember 2010 48 The complete code... 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. Ellipse2D bckg = new Ellipse2D.Double(0, 0, 404, 404); Point2D start = new Point2D.Double(117, 20); Point2D stop = new Point2D.Double(259, 395); float[] fractions = { 0.0f, 0.1f, 0.25f, 0.45f, 0.75f, 1.0f } Color[] colors = { new Color(189, 191, 190, 255), new Color(243, 243, 243, 255), new Color(243, 243, 243, 255), new Color(120, 116, 104, 255), new Color(129, 130, 122, 255), new Color(76, 76, 74, 255) } LinearGradientPaint gradient = new LinearGradientPaint(start, stop, fractions, colors); G2.setPaint(gradient); G2.fill(bckg); PAGE: 49 Donnerstag, 2. Dezember 2010 49 The worst case... PAGE: 50 Donnerstag, 2. Dezember 2010 50 A ,,simple" cloud PAGE: 51 Donnerstag, 2. Dezember 2010 51 A ,,simple" cloud PAGE: 51 Donnerstag, 2. Dezember 2010 51 A ,,simple" cloud PAGE: 51 Donnerstag, 2. Dezember 2010 51 A ,,simple" cloud PAGE: 51 Donnerstag, 2. Dezember 2010 51 A ,,simple" cloud PAGE: 51 Donnerstag, 2. Dezember 2010 51 You`ll need patience and stamina my friend... PAGE: 52 Donnerstag, 2. Dezember 2010 52 Is this the solution ? PAGE: 53 Donnerstag, 2. Dezember 2010 53 if (time == INFINITE) { answer = ,,YES"; } PAGE: 54 Donnerstag, 2. Dezember 2010 54 How do the competitors do it ? PAGE: 55 Donnerstag, 2. Dezember 2010 55 They convert graphics to code... var boxHeight:Number = 100; var boxWidth:Number = 50; var alphas:Array = [1, 1]; var ratios:Array = [0, 255]; var type:String = GradientType.RADIAL; var colors:Array = [0x00FF00, 0x000088]; var matrix:Matrix = new Matrix(); matrix.createGradientBox(boxWidth, boxHeight, boxRotation, tx, ty); PAGE: 56 Donnerstag, 2. Dezember 2010 56 Tools... Silverlight: Microsoft Expression Blend converts: Adobe Illustrator, Adobe Photoshop Flex: Adobe Flash Catalyst converts: Adobe Illustrator, Adobe Fireworks, Adobe Photoshop JavaFX: JavaFX 1.3 Production Suite converts: Adobe Illustrator, Adobe Photoshop, SVG PAGE: 57 Donnerstag, 2. Dezember 2010 57 PAGE: 58 Donnerstag, 2. Dezember 2010 58 And for Java??? PAGE: 58 Donnerstag, 2. Dezember 2010 58 The easy way PAGE: 59 Donnerstag, 2. Dezember 2010 59 Converting FXG to Java2D PAGE: 60 Donnerstag, 2. Dezember 2010 60 FXG ??? PAGE: 61 Donnerstag, 2. Dezember 2010 61 The FXG format Wikipedia says... FXG (Flash XML Graphics) is an XML graphics file format being developed by Adobe Systems, as well as handling the capabilities of Adobe Flash FXG is planned as a graphics interchange format for cross-application file support... Mark Anders noted that the first aim the specification was designed for was componentized graphics. PAGE: 62 Donnerstag, 2. Dezember 2010 62 FXGConverter Click to open webstart version PAGE: 63 Donnerstag, 2. Dezember 2010 63 FXG to Java2D converter PAGE: 64 Donnerstag, 2. Dezember 2010 64 FXG to Java2D converter PAGE: 64 Donnerstag, 2. Dezember 2010 64 FXG to Java2D converter Features Support for fxg files created by Adobe Fireworks CS4 (fxg 1.0) and CS5 (fxg 2.0) Restricted support for fxg files created by Adobe Illustrator CS4 Basic elements like ellipse, rect, path Basic strokes Restricted support for fonts Linear and radial gradients Inner- and dropshadows Layers will be taken into account Convert shapes only (without fill) Convert everything in one color Live conversion preview PAGE: 65 Donnerstag, 2. Dezember 2010 65 Converting the example PAGE: 66 Donnerstag, 2. Dezember 2010 66 DEMO Click to open youTube video FXG converter demo - convert rheinjug logo - convert CPU gauge CPU Gauge Demo PAGE: 67 Donnerstag, 2. Dezember 2010 67 The old workflow Draw the image (preferred in Adobe Fireworks) Create the component template Convert element to code by hand Convert element to code by hand Convert element to code by hand Convert element to code by hand Convert element to code by hand ... Call the drawImage() methods in the paintComponent() method Add the component logic to your code Done PAGE: 68 Donnerstag, 2. Dezember 2010 68 The new workflow Draw the image (preferred in Adobe Fireworks) Export the image to fxg Create the component template Convert the fxg file to code with the fxg converter Paste the code into your skeleton Call the drawImage() methods in the paintComponent() method Add the component logic to your code Done PAGE: 69 Donnerstag, 2. Dezember 2010 69 Knowing and Using the right tools... PAGE: 70 Donnerstag, 2. Dezember 2010 70 Allows you to do this... PAGE: 71 Donnerstag, 2. Dezember 2010 71 SteelSeries PAGE: 72 Donnerstag, 2. Dezember 2010 72 DEMO Click to open webstart demo PAGE: 73 Donnerstag, 2. Dezember 2010 73 The resume Using the layered images approach you will get... Advantages Easy to use (adoption from drawing programs is more easy) Draw once paint often (reduces object creation) Fast enough on todays hardware (standard desktop pc) Code looks cleaner (paintComponent() method does not look cluttered) Drawbacks Resource hungry (memory consumption) Initialization time (increases with no. of images) PAGE: 74 Donnerstag, 2. Dezember 2010 74 PAGE: 75 Donnerstag, 2. Dezember 2010 75 ur yo or f nx ha ... T on ti en tt a PAGE: 75 Donnerstag, 2. Dezember 2010 75 Find more information here... Books Swing Hacks, Joshua Marinacci & Chris Adamson, O`Reilly Filthy Rich Clients, Chet Haase & Romain Guy, Addison Wesley Desktop Java Live, Scott Delap, SourceBeat Java 2D Graphics, Jonathan Knudsen, O`Reilly Java 2D API Graphics, Vincent J. Hardy, Sun Microsystems Press Tutorials Drawing in code Part I Drawing in code Part II Blogs http://www.harmonic-code.org http://www.jug-muenster.de PAGE: Donnerstag, 2. Dezember 2010 76 76