diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java index 82c27df..89accf0 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java @@ -39,6 +39,9 @@ import java.awt.Stroke; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; +import java.awt.event.ContainerAdapter; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; import java.awt.geom.Rectangle2D; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -274,6 +277,37 @@ }; /** + * Listens to container nodes for changes to its contents. Any additions + * will automatically have double buffering turned off. + */ + private final ContainerListener doubleBufferRemover = new ContainerAdapter() { + public void componentAdded(ContainerEvent e) { + Component childComponent = e.getChild(); + if (childComponent != null && childComponent instanceof JComponent) { + disableDoubleBuffering(((JComponent) childComponent)); + } + }; + + /** + * Disables double buffering on every component in the hierarchy of the + * targetComponent. + * + * I'm assuming that the intent of the is method is that it should be + * called explicitly by anyone making changes to the hierarchy of the + * Swing component graph. + */ + private void disableDoubleBuffering(final JComponent targetComponent) { + targetComponent.setDoubleBuffered(false); + for (int i = 0; i < targetComponent.getComponentCount(); i++) { + final Component c = targetComponent.getComponent(i); + if (c instanceof JComponent) { + disableDoubleBuffering((JComponent) c); + } + } + } + }; + + /** * Create a new visual component wrapper for the specified Swing component. * * @param component Swing component to be wrapped @@ -287,7 +321,7 @@ component.addPropertyChangeListener(new PropertyChangeListener() { /** {@inheritDoc} */ public void propertyChange(final PropertyChangeEvent evt) { - reshape(); + updateBounds(); } }); @@ -303,7 +337,7 @@ } }); - reshape(); + updateBounds(); listenForCanvas(this); } @@ -321,7 +355,7 @@ * Ensures the bounds of the underlying component are accurate, and sets the * bounds of this PNode. */ - void reshape() { + public void updateBounds() { // Avoid setBounds if it is unnecessary // TODO: should we make sure this is called at least once // TODO: does this sometimes need to be called when size already equals @@ -470,33 +504,6 @@ return component; } - // TODO: make this private and internal by listenening for componentAdded on - // known components - // This disables double buffering on any new components; if you add - // components to the target jcomponent without disabling double buffering, - // then there may be many graphical artifacts. - /** - * Disables double buffering on the wrapped component and all of its - * children. - * - * I'm assuming that the intent of the is method is that it should be called - * explicitly by anyone making changes to the hierarchy of the Swing - * component graph. - */ - private void componentHierarchyChanged() { - disableDoubleBuffering(component); - } - - private void disableDoubleBuffering(final JComponent targetComponent) { - targetComponent.setDoubleBuffered(false); - for (int i = 0; i < targetComponent.getComponentCount(); i++) { - final Component c = targetComponent.getComponent(i); - if (c instanceof JComponent) { - disableDoubleBuffering((JComponent) c); - } - } - } - /** * We need to turn off double buffering of Swing components within Piccolo * since all components contained within a native container use the same @@ -521,16 +528,17 @@ c.addComponentListener(new ComponentAdapter() { public void componentResized(final ComponentEvent e) { - reshape(); + updateBounds(); } public void componentShown(final ComponentEvent e) { - reshape(); + updateBounds(); } }); if (c instanceof Container) { initializeChildren((Container) c); + ((Container) c).addContainerListener(doubleBufferRemover); } if (c instanceof JComponent) { @@ -646,7 +654,7 @@ if (newCanvas != null) { canvas = newCanvas; canvas.addPSwing(this); - reshape(); + updateBounds(); repaint(); canvas.invalidate(); canvas.revalidate(); diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingRepaintManager.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingRepaintManager.java index e09a7ad..4412b80 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingRepaintManager.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingRepaintManager.java @@ -191,7 +191,7 @@ public void run() { capturedComponent.validate(); final PSwing pSwing = (PSwing) capturedComponent.getClientProperty(PSwing.PSWING_PROPERTY); - pSwing.reshape(); + pSwing.updateBounds(); } }); } diff --git a/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java b/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java index 41eeb18..9e13009 100644 --- a/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java +++ b/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java @@ -75,8 +75,8 @@ final JPanel panel = new JPanel(); new PSwing(panel) { - protected void reshape() { - super.reshape(); + public void updateBounds() { + super.updateBounds(); reshaped[0] = true; } @@ -116,6 +116,15 @@ }); } + + public void testAddingSwingComponentToWrappedHierarchyMakesItNotDoubleBuffer() { + final JPanel panel = new JPanel(); + final PSwing pSwing = new PSwing(panel); + final JComponent child = new JLabel("Test Component"); + child.setDoubleBuffered(true); + panel.add(child); + assertFalse(child.isDoubleBuffered()); + } public void assertDelayedSuccess(String message, int delay, Predicate p) { int remainingTries = delay / 50;