JDK-4356383 : Support lightweight component printing in headless mode
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0
  • Priority: P4
  • Status: Closed
  • Resolution: Won't Fix
  • OS: generic
  • CPU: generic
  • Submitted: 2000-07-26
  • Updated: 2001-11-12
  • Resolved: 2001-11-12
Related Reports
Relates :  
Description
Right now under the headless java specification, there is no means for swing components to be sent to a printer.  The problem is that a top-level window is required for components to be seen as "showing" and to have valid lightweight peers.
An advanced application programmer can simulate a top-level container, but such a thing is not intuitive (and it took myself, an AWT core programmer, several tries to get it right).
See the suggested fix; this is a new RFE to track the feature.

Comments
WORK AROUND Only sophistocated application programmers can truly get around this problem by creating their own simulated top-level container.
11-06-2004

SUGGESTED FIX /* * %W% %E% * * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. * * This software is the proprietary information of Sun Microsystems, Inc. * Use is subject to license terms. * */ package javax.swing; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.image.BufferedImage; import javax.swing.*; import javax.swing.plaf.basic.BasicPanelUI; /** * The <code>JTopLevel</code> class represents a simulated top-level window that * paints directly to an image. This can be useful for off-screen printing, or * for direct rendering to an image. * @author Michael Martak * @since 1.4 */ public class JTopLevel extends JPanel { protected Image image; protected Point offset; private boolean resizing = false; /** * Creates a new <code>JTopLevel</code> object from an image, an offset, * and a size. * @param image the image on which to draw * @param x the x offset on the image for drawing * @param y the y offset on the image for drawing * @param width the width of the area of the image to use to draw * @param height the height of the area of the image to use to draw */ public JTopLevel(Image image, int x, int y, int width, int height) { this.image = image; Dimension d = new Dimension(width, height); offset = new Point(x,y); setSize(d); setPreferredSize(d); } /** * Creates a new <code>JTopLevel</code> object from an image and a size. * @param image the image on which to draw * @param width the width of the area of the image to use to draw * @param height the height of the area of the image to use to draw */ public JTopLevel(Image image, int width, int height) { this(image, 0, 0, width, height); } /** * Creates a new <code>JTopLevel</code> object from a buffered image. * @param image the image on which to draw */ public JTopLevel(BufferedImage image) { this(image, image.getWidth(), image.getHeight()); } /** * Overridden to force any lightweight peers to be created */ protected void addImpl(Component comp, Object constraints, int index) { super.addImpl(comp, constraints, index); comp.addNotify(); } /** * Overridden to fool the components into thinking we are showing, though * we are technically "showing" off-screen. */ public boolean isShowing() { return !resizing; } /** * Since we weren't created with a particular graphics configuration, * we override this to return the default. */ public GraphicsConfiguration getGraphicsConfiguration() { if (GraphicsEnvironment.isHeadless()) { return null; } return GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().getDefaultConfiguration(); } /** * @return <code>null</code> */ public Container getParent() { return null; } /** * Overridden to return the graphics from our image */ public Graphics getGraphics() { Graphics g = image.getGraphics(); Dimension d = getPreferredSize(); g.setClip(getX(), getY(), d.width, d.height); return g; } /** * Overridden to paint from our image. To draw the components */ public void paint(Graphics g) { Dimension d = getPreferredSize(); g.drawImage(image, getX(), getY(), d.width, d.height, this); } /** * Overridden to always return the preferred size */ public Dimension size() { return getPreferredSize(); } /** * Overridden to always return the offset and preferred size */ public Rectangle bounds() { Dimension d = getPreferredSize(); return new Rectangle(getX(), getY(), d.width, d.height); } /** * Overridden to always return the offset */ public int getX() { return offset.x; } /** * Overridden to always return the offset */ public int getY() { return offset.y; } /** * Overridden to always return the preferred size */ public int getWidth() { return getPreferredSize().width; } /** * Overridden to always return the preferred size */ public int getHeight() { return getPreferredSize().height; } /** * Overridden so that we don't try to paint while resizing */ public void reshape(int x, int y, int width, int height) { resizing = true; super.reshape(x, y, width, height); resizing = false; } /** * Overridden to create a new image */ public Image createImage(int width, int height) { return new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); } /** * Redraws the component to the background image. */ public void redraw() { Graphics g = getGraphics(); paintComponent(g); paintBorder(g); paintChildren(g); g.dispose(); } /** * Overridden to set the UI object and redraw */ public void show() { setUI(BasicPanelUI.createUI(this)); redraw(); } /** * Lays out the components in this object and refreshes the background * image. */ public void pack() { doLayout(); show(); } }
11-06-2004

PUBLIC COMMENTS A yet unaddressed problem with the headless specification.
10-06-2004

EVALUATION This would make more sense as an article. ###@###.### 2001-11-12
12-11-2001