强制paintAll()绘制一个不可见的JPanel及其组件?

时间:2013-01-08 13:34:56

标签: java swing graphics printing bufferedimage

我正在努力将一系列JPanels打印到Printable,这是一个基本的打印界面,它提供了一个绘制想要打印的图形对象。如果我有一个“实时”JPanel,那就是在UI的某个地方,一切都很好。

但是,如果我创建一个JPanel并且从不将其添加到UI,则printAll()似乎什么都不做。将代码减少为SSCCE:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class SSCCEPaintInvisible
{
    public static void main(String[] args)
    {
        /* Create an JPanel with a JLabel */
        JPanel panel = new JPanel();
        //panel.setLayout(new FlowLayout());
        JLabel label = new JLabel("Hello World");
        panel.add(label);
        //label.invalidate();
        //panel.invalidate();

        /* Record a picture of the panel */
        BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_4BYTE_ABGR);
        Graphics g = image.getGraphics();

        /* Draw something to ensure we're drawing */
        g.setColor(Color.BLACK);
        g.drawLine(0, 0, 100, 100);

        /* Attempt to draw the panel we created earlier */ 
        panel.paintAll(g);  // DOES NOTHING. :(

        /* Display a frame to test if the graphics was captured */
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JLabel label2 = new JLabel( new ImageIcon(image) );
        frame.add(label2);
        frame.pack();

        frame.setVisible(true);
            // shows ONLY the black line we drew in the Graphics
    }
}

如果我为面板创建一个JFrame并将面板添加到JFrame并在调用paintAll()之前使JFrame可见,则代码会按预期将UI捕获到Graphic。当然,这会在屏幕上闪烁JFrame以进行打印。

有没有办法将从未添加到UI的JPanel渲染到Graphics对象中?谢谢!

1 个答案:

答案 0 :(得分:3)

来自@Kleopatra答案的提示。

SSCCEPaintInvisible

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

public class SSCCEPaintInvisible
{
    public static void main(String[] args)
    {
        /* Create an JPanel with a JLabel */
        JPanel panel = new JPanel();

        JLabel label = new JLabel("Hello World");
        panel.add(label);
        // Next 3 are very important!
        panel.setSize(panel.getPreferredSize());
        panel.addNotify();
        panel.doLayout();

        /* Record a picture of the panel */
        BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_4BYTE_ABGR);
        Graphics g = image.getGraphics();

        /* Draw something to ensure we're drawing */
        g.setColor(Color.BLACK);
        g.drawLine(0, 0, 100, 100);

        /* Attempt to draw the panel we created earlier */
        panel.paintAll(g);  // DOES NOTHING. :(

        /* Display a frame to test if the graphics was captured */
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JLabel label2 = new JLabel( new ImageIcon(image) );
        frame.add(label2);
        frame.pack();

        frame.setVisible(true);
            // shows ONLY the black line we drew in the Graphics
    }
}

正如@GagandeepBali所指出的,这个GUI不是在EDT上创建的。如果在EDT上没有对GUI进行更改,结果将无法预测。见Concurrency in Swing&特别是Initial Threads了解更多细节。