打印一个大的Swing组件

我有一个JScrollPane中的自定义表格的Swing窗体(它只是一个JPanel,而不是一个JTable子类),我试图让它打印。 如果我只是把整个框架发送到打印机,滚动窗格切断,如果我调整框架的大小,滚动窗格的内容的大小,某种内部障碍停止JFrame成为超过1100像素高。

另一种方法是创build对话框的内容窗格而不将其附加到根JFrame上,因为在这种情况下,JPanel的大小不受限制。 但是为了让组件自己放置并调整到适当的大小,我似乎需要使面板可显示,这意味着至less将其添加到JFrame中并调用JFrame.pack(),但是1100像素限制回来。

这是我打印组件的代码:

public static void print(final Component comp) { final float SCALE = .5f; PrinterJob job = PrinterJob.getPrinterJob(); job.setPrintable(new Printable() { public int print(Graphics g, PageFormat pf, int page) throws PrinterException { if (page * pf.getImageableHeight() >= SCALE * comp.getHeight()) return NO_SUCH_PAGE; ((Graphics2D)g).translate(pf.getImageableX(), pf.getImageableY() - page * pf.getImageableHeight()); ((Graphics2D)g).scale(SCALE, SCALE); comp.printAll(g); return PAGE_EXISTS; } }); if (job.printDialog()) try { job.print(); } catch (PrinterException ex) {} } 

如果我这样做,该组件具有零大小:

 JPanel c = createPanel(); // This JPanel has a JScrollPane in it with its // preferredSize equal to that of its viewport component // (which is not what I do to show the dialog normally) print(c); 

如果我这样做,该组件具有正确的大小,但打印为纯灰色,因为子组件尚未布置:

 JPanel c = createPanel(); c.setSize(c.getPeferredSize()); print(c); 

这些似乎没有什么区别:

 JPanel c = createPanel(); c.validate(); c.revalidate(); c.repaint(); print(c); 

这使面板更大,但停在大约一页半大(1100px):

 JPanel c = createPanel(); JFrame f = new JFrame(); f.setContentPane(c); f.pack(); print(c); 

我在这里摆脱了排列。 有没有人知道(a)如何改变操作系统的最大帧大小,(b)如何布局和绘制一个屏幕外的组件,或(c)如何直接打印一个Swing组件,而不需要绘制它(?) 。 帮助表示赞赏。

使用自定义面板的paint()方法,将内容渲染到BufferedImage

附录:这是一个更完整的方法示例,它只是将组件缩放一半。 您需要在实际应用程序中保留长宽比。

在这里输入图像描述

 import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; /** @see https://stackoverflow.com/questions/7026822 */ public class PanelPaint extends JPanel { private static final double SCALE = 0.5; public PanelPaint() { super(new GridLayout(0, 1)); final MyPanel panel = new MyPanel(); JScrollPane scroll = new JScrollPane(panel); scroll.getViewport().setPreferredSize(new Dimension(320, 240)); this.add(scroll); EventQueue.invokeLater(new Runnable() { @Override public void run() { add(new JLabel(new ImageIcon(createImage(panel)))); } }); } private BufferedImage createImage(MyPanel panel) { Dimension size = panel.getPreferredSize(); BufferedImage image = new BufferedImage( size.width, size.height, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = image.createGraphics(); panel.paint(g2d); g2d.dispose(); AffineTransform at = new AffineTransform(); at.scale(SCALE, SCALE); AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR); return scaleOp.filter(image, null); } private static class MyPanel extends JPanel { private static final int N = 16; public MyPanel() { super(true); this.setLayout(new GridLayout(N, N)); for (int i = 0; i < N * N; i++) { this.add(new JLabel(String.valueOf(i) + " ")); } } } private void display() { JFrame f = new JFrame("PanelPaint"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(this); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new PanelPaint().display(); } }); } } 

如此处所示,您可以缩放渲染以适应目标的MediaPrintableArea ,或者使用getSubimage()将内容getSubimage()分割成页面。

您必须在不使用滚动条的情况下打印组件。 该scrollpane将始终只打印可见的内容。

如果您没有访问createPanel()方法,并且此方法中的面板只包含滚动窗格,则可以通过以下方式获取滚动窗格包含的组件:

 JPanel panel = createPanel(); print(((JScrollPane)panel.getComponents()[0]).getViewport()); 

但是如果你的数据是格式化的,你也可以使用JTable。 JTable拥有自己的强大的print()方法。 更多信息请参见http://download.oracle.com/javase/tutorial/uiswing/misc/printtable.html

由于JScrollPane中的组件可以具有任意大小,即使它可以显示,我的解决scheme是尝试这个:

 JPanel c = createPanel(); JFrame f = new JFrame(); f.getContentPane().add(new JScrollPane(c)); f.pack(); print(c); 

这样我就可以validationJPanel,而不会将其大小限制为JFrame的最大大小。 它也具有“无限分辨率”的外观,可以直接打印组件,而不需要像build议的垃圾桶那样的双缓冲。