3

ヘッドレス モードで JPanel を BufferedImage にペイントしたいと思います (画面に GUI がまったく表示されません)。

final JPanel panel = createPanel();
panel.setSize(panel.getPreferredSize());
panel.validate();

//  JFrame frame = new JFrame();
//  frame.getContentPane().add(panel);
//  frame.pack();
//  frame.setVisible(true);

final BufferedImage image = new BufferedImage(
            panel.getBounds().width, 
            panel.getBounds().height, 
            BufferedImage.TYPE_INT_ARGB
);

final Graphics2D gc = image.createGraphics();
gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
gc.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

try {
    panel.paint(gc);
    ...save the image somewhere...
} finally {
    gc.dispose();
}

しかし、パネルを重いコンポーネントに入れて画面に表示するまで、常に空の画像が表示されます(コメント付きのコードを参照)。見せたくないのですが、このアプリケーションはサーバー上で実行されます。

SSCCE は次のとおりです。

    public class Example {

    private static JPanel createPanel() {
        final JPanel panel = new JPanel(new GridBagLayout());           
        final JLabel label = new JLabel("Yeah, it's working!", SwingConstants.CENTER);
        label.setFont(new Font("Arial", Font.PLAIN, 12));           
        final GridBagConstraints constraints = new GridBagConstraints();
        constraints.fill = GridBagConstraints.BOTH;
        constraints.weightx = 1;
        constraints.weightx = 1;
        panel.add(label, constraints);          
        return panel;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                final JPanel panel = createPanel();
                panel.setSize(panel.getPreferredSize());
                panel.validate();

    //              JFrame frame = new JFrame();
    //              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    //              frame.getContentPane().add(panel);
    //              frame.pack();
    //              frame.setVisible(true);

                final BufferedImage image = new BufferedImage(
                        panel.getBounds().width, 
                        panel.getBounds().height, 
                        BufferedImage.TYPE_INT_ARGB
                );    
                final Graphics2D gc = image.createGraphics();
                gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                gc.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);    
                try {
                    panel.paint(gc);
                    ImageIO.write(image, "png", new File("image.png"));
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    gc.dispose();
                }                   
            }
        });
    }    
}
4

4 に答える 4

4

コンポーネントが実現されるまで、コンポーネントのサイズはゼロであるため、ペイント方法は機能しません。

画面イメージを確認してください。パネルで doLayout() を呼び出して、すべてのコンポーネントが有効なサイズであることを確認することで、この問題を処理します。

于 2013-06-10T15:13:09.397 に答える
3

これは、単純なラベルを画像ファイルに描画し、画像ファイルを開く (デスクトップ コンピューターの場合) スニペットです。

import java.awt.Desktop;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JLabel;

public class Test {

    public static void main(String[] args) throws IOException {
        JLabel label = new JLabel("Hello world");
        label.setSize(label.getPreferredSize());
        BufferedImage image = new BufferedImage(label.getWidth(), label.getHeight(), BufferedImage.TYPE_INT_ARGB);
        label.paint(image.getGraphics());
        File output = new File("C:\\test\\hello world.png");
        if (!output.getParentFile().exists()) {
            output.getParentFile().mkdirs();
        }
        ImageIO.write(image, "png", output);
        Desktop.getDesktop().open(output);
    }

}

編集(SSCCEを使用):

呼び出すのvalidate()ではなくdoLayout()、パネルで呼び出します (ネストされたパネルがある場合は、再帰的に呼び出すようにしてください)。

import java.awt.Desktop;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;

public class Example {

    private static JLabel label;

    private static JPanel createPanel() {
        final JPanel panel = new JPanel(new GridBagLayout());

        label = new JLabel("Yeah, it's working!", SwingConstants.CENTER);
        label.setFont(new Font("Arial", Font.PLAIN, 12));

        final GridBagConstraints constraints = new GridBagConstraints();
        constraints.fill = GridBagConstraints.BOTH;
        constraints.weightx = 1;
        constraints.weightx = 1;
        panel.add(label, constraints);

        return panel;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                final JPanel panel = createPanel();
                panel.setSize(panel.getPreferredSize());
                panel.doLayout();
                System.err.println(label.getSize() + "");
                // JFrame frame = new JFrame();
                // frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                // frame.getContentPane().add(panel);
                // frame.pack();
                // frame.setVisible(true);

                final BufferedImage image = new BufferedImage(panel.getBounds().width, panel.getBounds().height,
                        BufferedImage.TYPE_INT_ARGB);

                final Graphics2D gc = image.createGraphics();
                gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                gc.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

                try {
                    panel.paint(gc);
                    File output = new File("image.png");
                    ImageIO.write(image, "png", output);
                    Desktop.getDesktop().open(output);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    gc.dispose();
                }

            }
        });
    }
}
于 2013-06-10T15:29:22.510 に答える
1

印刷/ペイントしようとしているルート コンポーネントを呼び出すaddNotifyと、問題も解決します。問題の核心は、コンテナに「ピア」がない限り、検証呼び出しが短絡することです。呼び出しaddNotifyによりピアが初期化され、後続の呼び出しがComponent.validate非ヘッドレス シナリオの場合と同様に機能できるようになります。

サブコンポーネントがレイアウトされていないdoLayoutためにコンポーネントがより深くネストされている場合、呼び出しが機能しないため、これを代替ソリューションとして送信します。doLayout(ただし、camickr の回答で言及されている ScreenImage クラスは、doLayout を再帰的に呼び出すことでこれに対処しています。)

于 2017-08-30T14:42:06.767 に答える