Revision: 1122
Author:   atdixon
Date:     Mon Mar 28 21:12:27 2011
Log: Issue 173; Introduced useBufferedPainting option to PSwing. Used much of the original buffered painting implementation details from Piccolo2D 1.2. Also added PSwingExample4 which extends PSwingExample1 but turns on buffered painting for all of the PSwing nodes.
http://code.google.com/p/piccolo2d/source/detail?r=1122

Added:
/piccolo2d.java/branches/release-1.3/examples/src/main/java/edu/umd/cs/piccolo/examples/pswing/PSwingExample4.java
Modified:
/piccolo2d.java/branches/release-1.3/examples/src/main/java/edu/umd/cs/piccolo/examples/pswing/PSwingExample1.java /piccolo2d.java/branches/release-1.3/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java

=======================================
--- /dev/null
+++ /piccolo2d.java/branches/release-1.3/examples/src/main/java/edu/umd/cs/piccolo/examples/pswing/PSwingExample4.java Mon Mar 28 21:12:27 2011
@@ -0,0 +1,23 @@
+package edu.umd.cs.piccolo.examples.pswing;
+
+import edu.umd.cs.piccolox.pswing.PSwing;
+
+import javax.swing.JComponent;
+
+/**
+ * Extends {@link PSwingExample1} but uses {@link edu.umd.cs.piccolox.pswing.PSwing#setUseBufferedPainting(boolean)}
+ * for {@link edu.umd.cs.piccolox.pswing.PSwing}s.
+ */
+public class PSwingExample4 extends PSwingExample1 {
+
+    public static void main(final String[] args) {
+        new PSwingExample4().run();
+    }
+
+    protected PSwing createPSwing(JComponent component) {
+        PSwing pSwing = new PSwing(component);
+        pSwing.setUseBufferedPainting(true);
+        return pSwing;
+    }
+
+}
=======================================
--- /piccolo2d.java/branches/release-1.3/examples/src/main/java/edu/umd/cs/piccolo/examples/pswing/PSwingExample1.java Tue Mar 15 15:28:41 2011 +++ /piccolo2d.java/branches/release-1.3/examples/src/main/java/edu/umd/cs/piccolo/examples/pswing/PSwingExample1.java Mon Mar 28 21:12:27 2011
@@ -28,16 +28,18 @@
  */
 package edu.umd.cs.piccolo.examples.pswing;

-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
+import edu.umd.cs.piccolo.PNode;
+import edu.umd.cs.piccolo.event.PZoomEventHandler;
+import edu.umd.cs.piccolo.nodes.PText;
+import edu.umd.cs.piccolox.pswing.PComboBox;
+import edu.umd.cs.piccolox.pswing.PSwing;
+import edu.umd.cs.piccolox.pswing.PSwingCanvas;

 import javax.swing.BorderFactory;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JColorChooser;
+import javax.swing.JComponent;
 import javax.swing.JFrame;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
@@ -48,20 +50,27 @@
 import javax.swing.border.LineBorder;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
-
-import edu.umd.cs.piccolo.PNode;
-import edu.umd.cs.piccolo.event.PZoomEventHandler;
-import edu.umd.cs.piccolo.nodes.PText;
-import edu.umd.cs.piccolox.pswing.PComboBox;
-import edu.umd.cs.piccolox.pswing.PSwing;
-import edu.umd.cs.piccolox.pswing.PSwingCanvas;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;

 /**
  * User: Sam Reid Date: Jul 11, 2005 Time: 12:15:55 PM
  */

 public class PSwingExample1 {
+
     public static void main(final String[] args) {
+        new PSwingExample1().run();
+    }
+
+    protected PSwing createPSwing(JComponent component) {
+        return new PSwing(component);
+    }
+
+    protected void run() {
         final PSwingCanvas pCanvas = new PSwingCanvas();
         final PText pText = new PText("PText");
         pCanvas.getLayer().addChild(pText);
@@ -86,13 +95,13 @@
System.out.println("TestZSwing.actionPerformed!!!!!!!!!!!!!!*********************");
             }
         });
-        final PSwing pSwing = new PSwing(jButton);
+        final PSwing pSwing = createPSwing(jButton);
         pCanvas.getLayer().addChild(pSwing);
         pSwing.repaint();

         final JSpinner jSpinner = new JSpinner();
jSpinner.setPreferredSize(new Dimension(100, jSpinner.getPreferredSize().height));
-        final PSwing pSpinner = new PSwing(jSpinner);
+        final PSwing pSpinner = createPSwing(jSpinner);
         pCanvas.getLayer().addChild(pSpinner);
         pSpinner.translate(0, 150);

@@ -107,20 +116,20 @@
System.out.println("TestPSwing.JChekbox.stateChanged@" + System.currentTimeMillis());
             }
         });
-        final PSwing pCheckBox = new PSwing(jcb);
+        final PSwing pCheckBox = createPSwing(jcb);
         pCanvas.getLayer().addChild(pCheckBox);
         pCheckBox.translate(100, 0);

         // Growable JTextArea
final JTextArea textArea = new JTextArea("This is a growable TextArea.\nTry it out!");
         textArea.setBorder(new LineBorder(Color.blue, 3));
-        PSwing swing = new PSwing(textArea);
+        PSwing swing = createPSwing(textArea);
         swing.translate(150, 150);
         pCanvas.getLayer().addChild(swing);

         // A Slider
         final JSlider slider = new JSlider();
-        final PSwing pSlider = new PSwing(slider);
+        final PSwing pSlider = createPSwing(slider);
         pSlider.translate(200, 200);
         pCanvas.getLayer().addChild(pSlider);

@@ -129,26 +138,26 @@
         tree.setEditable(true);
         final JScrollPane p = new JScrollPane(tree);
         p.setPreferredSize(new Dimension(150, 150));
-        final PSwing pTree = new PSwing(p);
+        final PSwing pTree = createPSwing(p);
         pCanvas.getLayer().addChild(pTree);
         pTree.translate(0, 250);

         // A JColorChooser - also demonstrates JTabbedPane
         final JColorChooser chooser = new JColorChooser();
-        final PSwing pChooser = new PSwing(chooser);
+        final PSwing pChooser = createPSwing(chooser);
         pCanvas.getLayer().addChild(pChooser);
         pChooser.translate(100, 300);

         final JPanel myPanel = new JPanel();
myPanel.setBorder(BorderFactory.createTitledBorder("Titled Border"));
         myPanel.add(new JCheckBox("CheckBox"));
-        final PSwing panelSwing = new PSwing(myPanel);
+        final PSwing panelSwing = createPSwing(myPanel);
         pCanvas.getLayer().addChild(panelSwing);
         panelSwing.translate(400, 50);

         // A Slider
         final JSlider slider2 = new JSlider();
-        final PSwing pSlider2 = new PSwing(slider2);
+        final PSwing pSlider2 = createPSwing(slider2);
         pSlider2.translate(200, 200);
         final PNode root = new PNode();
         root.addChild(pSlider2);
@@ -163,7 +172,7 @@
final String[] listItems = { "Summer Teeth", "Mermaid Avenue", "Being There", "A.M." };
         final PComboBox box = new PComboBox(listItems);
         comboPanel.add(box);
-        swing = new PSwing(comboPanel);
+        swing = createPSwing(comboPanel);
         swing.translate(200, 230);
         pCanvas.getLayer().addChild(swing);
box.setEnvironment(swing, pCanvas);// has to be done manually at present
@@ -171,7 +180,7 @@
         // Revalidate and repaint
         pCanvas.revalidate();
         pCanvas.repaint();
-
+
pCanvas.getCamera().animateViewToCenterBounds(pCanvas.getLayer().getFullBounds(), true, 1200);
     }

=======================================
--- /piccolo2d.java/branches/release-1.3/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java Wed Aug 25 10:07:08 2010 +++ /piccolo2d.java/branches/release-1.3/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java Mon Mar 28 21:12:27 2011
@@ -28,6 +28,14 @@
  */
 package edu.umd.cs.piccolox.pswing;

+import edu.umd.cs.piccolo.PCamera;
+import edu.umd.cs.piccolo.PLayer;
+import edu.umd.cs.piccolo.PNode;
+import edu.umd.cs.piccolo.util.PBounds;
+import edu.umd.cs.piccolo.util.PPaintContext;
+
+import javax.swing.JComponent;
+import javax.swing.RepaintManager;
 import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Component;
@@ -40,7 +48,8 @@
 import java.awt.event.ContainerAdapter;
 import java.awt.event.ContainerEvent;
 import java.awt.event.ContainerListener;
-import java.awt.geom.Rectangle2D;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.io.IOException;
@@ -49,15 +58,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;

-import javax.swing.JComponent;
-import javax.swing.RepaintManager;
-
-import edu.umd.cs.piccolo.PCamera;
-import edu.umd.cs.piccolo.PLayer;
-import edu.umd.cs.piccolo.PNode;
-import edu.umd.cs.piccolo.util.PBounds;
-import edu.umd.cs.piccolo.util.PPaintContext;
-
 /*
  This message was sent to Sun on August 27, 1999

@@ -204,6 +204,11 @@
     /** Temporary repaint bounds. */
     private static final PBounds TEMP_REPAINT_BOUNDS2 = new PBounds();

+    /** For use when buffered painting is enabled. */
+ private static final Color BUFFER_BACKGROUND_COLOR = new Color(0, 0, 0, 0);
+
+ private static final AffineTransform IDENTITY_TRANSFORM = new AffineTransform();
+
     /** Default Greek threshold, <code>0.3d</code>. */
     private static final double DEFAULT_GREEK_THRESHOLD = 0.3d;

@@ -213,6 +218,15 @@
     /** Swing component for this Swing node. */
     private JComponent component = null;

+    /**
+     * Whether or not to use buffered painting.
+     * @see {@link #paint(java.awt.Graphics2D)}
+     */
+    private boolean useBufferedPainting = false;
+
+    /** Used when buffered painting is enabled. */
+    private BufferedImage buffer;
+
     /** Minimum font size. */
     private double minFontSize = Double.MAX_VALUE;

@@ -324,6 +338,22 @@
public PSwing(final PSwingCanvas swingCanvas, final JComponent component) {
         this(component);
     }
+
+    /**
+ * If true {@link PSwing} will paint the {@link JComponent} to a buffer with no graphics + * transformations applied and then paint the buffer to the target transformed + * graphics context. On some platforms (such as Mac OS X) rendering {@link JComponent}s to + * a transformed context is slow. Enabling buffered painting gives a significant performance + * boost on these platforms; however, at the expense of a lower-quality drawing result at larger
+     * scales.
+     */
+    public void setUseBufferedPainting(final boolean useBufferedPainting) {
+        this.useBufferedPainting = useBufferedPainting;
+    }
+
+    public boolean isUseBufferedPainting() {
+        return this.useBufferedPainting;
+    }

     /**
* Ensures the bounds of the underlying component are accurate, and sets the
@@ -471,13 +501,48 @@

         final RenderingHints oldHints = g2.getRenderingHints();

- g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
-        component.paint(g2);
+        if (useBufferedPainting) {
+            Graphics2D bufferedGraphics = getBufferedGraphics(g2);
+            component.paint(bufferedGraphics);
+            g2.drawRenderedImage(buffer, IDENTITY_TRANSFORM);
+        } else {
+ g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
+            component.paint(g2);
+        }

         g2.setRenderingHints(oldHints);

         manager.unlockRepaint(component);
     }
+
+    private Graphics2D getBufferedGraphics(Graphics2D source) {
+        final Graphics2D bufferedGraphics;
+        if(!isBufferValid()) {
+ // Get the graphics context associated with a new buffered image. + // Use TYPE_INT_ARGB_PRE so that transparent components look good on Windows. + buffer = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
+            bufferedGraphics = buffer.createGraphics();
+        }
+        else {
+ // Use the graphics context associated with the existing buffered image
+            bufferedGraphics = buffer.createGraphics();
+            // Clear the buffered image to prevent artifacts on Macintosh
+            bufferedGraphics.setBackground(BUFFER_BACKGROUND_COLOR);
+ bufferedGraphics.clearRect(0, 0, component.getWidth(), component.getHeight());
+        }
+        bufferedGraphics.setRenderingHints(source.getRenderingHints());
+        return bufferedGraphics;
+    }
+
+    /**
+     * Tells whether the buffer for the image of the Swing components
+     * is currently valid.
+     *
+     * @return true if the buffer is currently valid
+     */
+    private boolean isBufferValid() {
+ return !(buffer == null || buffer.getWidth() != component.getWidth() || buffer.getHeight() != component.getHeight());
+    }

     /**
* Repaints the specified portion of this visual component. Note that the

--
Piccolo2D Developers Group: http://groups.google.com/group/piccolo2d-dev?hl=en

Reply via email to