简体   繁体   English

我可以从JPanel创建BufferedImage而无需在JFrame中呈现吗?

[英]Can I create a BufferedImage from a JPanel without rendering in a JFrame?

Is it possible to create a BufferedImage from a JPanel without first rendering it in a JFrame? 是否可以从JPanel创建BufferedImage而无需先在JFrame中呈现它? I've searched everywhere I can think of and cannot find an answer. 我搜遍了我能想到的任何地方,找不到答案。 Can anyone help? 有人可以帮忙吗?

Here is some sample code. 这是一些示例代码。 If I don't un-comment the JFrame code, my BufferedImage is blank. 如果我不取消注释JFrame代码,我的BufferedImage是空白的。

    test(){
//      JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        Dimension dim = new Dimension(50,50);
        panel.setMinimumSize(dim);
        panel.setMaximumSize(dim);
        panel.setPreferredSize(dim);
        JLabel label = new JLabel("hello");
        panel.add(label);
//      frame.add(panel);
//      frame.pack();
        BufferedImage bi = getScreenShot(panel);

        //...code that saves bi to a jpg
    }

    private BufferedImage getScreenShot(JPanel panel){
        BufferedImage bi = new BufferedImage(panel.getWidth(), panel.getHeight(), BufferedImage.TYPE_INT_ARGB);
        panel.paint(bi.getGraphics());
        return bi;
    }

See this answer to Swing: Obtain Image of JFrame as well as Why does the JTable header not appear in the image? 请参阅Swing的 答案 :获取JFrame的图像以及为什么JTable标题没有出现在图像中? for tips on painting components that have not yet been rendered. 有关绘制尚未渲染的组件的提示。 I expect the fix to your problem is shown in the label of LabelRenderTest.java . 我希望您的问题的修复程序显示在LabelRenderTest.java的标签中。

JLabel textLabel = new JLabel(title);
textLabel.setSize(textLabel.getPreferredSize());

Update 更新

Dimension dim = new Dimension(50,50);
panel.setSize(dim);  // very important!
panel.setMinimumSize(dim);
panel.setMaximumSize(dim);
panel.setPreferredSize(dim);
// ...

Or here is the complete source. 或者这是完整的来源。 The size of the label also needs to be set. 还需要设置标签的大小。

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

import javax.swing.*;

public class RenderTest {

    RenderTest() {
        JPanel panel = new JPanel();
        panel.setBackground(Color.RED);
        Dimension dim = new Dimension(50,50);
        panel.setSize(dim);
        panel.setMinimumSize(dim);
        panel.setMaximumSize(dim);
        panel.setPreferredSize(dim);
        JLabel label = new JLabel("hello");
        label.setSize(label.getPreferredSize());
        panel.add(label);

        BufferedImage bi = getScreenShot(panel);
        JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
    }

    private BufferedImage getScreenShot(JPanel panel){
        BufferedImage bi = new BufferedImage(
            panel.getWidth(), panel.getHeight(), BufferedImage.TYPE_INT_ARGB);
        panel.paint(bi.getGraphics());
        return bi;
    }

    public static void main(String[] args) {
        new RenderTest();
    }
}

EDIT2: Basically Andrew Thompson is right in his answer, a frame is not necessary. 编辑2:基本上安德鲁汤普森的答案是正确的,一个框架是没有必要的。 At the same time it can be practical to have one, because a call to pack() will make the layout managers work. 同时拥有一个是实用的,因为对pack()的调用将使布局管理器工作。 I deleted the first part of my original answer, left is the memory-related part. 我删除了原始答案的第一部分,左边是与记忆相关的部分。 Note that calling dispose on the Graphics is still needed even without a frame. 请注意,即使没有帧,仍然需要在Graphics上调用dispose。

About your running out of heap space when using frames: this should not happen. 关于使用框架时堆空间的用尽:这不应该发生。 Probably you only need to call dispose() on the frames when you are done with them. 可能你只需要在框架上调用dispose()就可以了。 If that does not help, I would suggest asking it in a separate question. 如果这没有帮助,我建议在一个单独的问题中提出。 From the dispose docs: 从dispose文档:

Releases all of the native screen resources used by this Window, its subcomponents, and all of its owned children. 释放此Window,其子组件及其所有子组件使用的所有本机屏幕资源。 That is, the resources for these Components will be destroyed, any memory they consume will be returned to the OS, and they will be marked as undisplayable. 也就是说,这些组件的资源将被销毁,它们使用的任何内存都将返回给操作系统,并且它们将被标记为不可显示。 (...) Note: When the last displayable window within the Java virtual machine (VM) is disposed of, the VM may terminate. (...)注意:当处理Java虚拟机(VM)中的最后一个可显示窗口时,VM可能会终止。

EDIT: some more thoughts: 编辑:更多的想法:

  • reusing the same JFrame object should also work. 重用相同的JFrame对象也应该有效。 Add panel, call pack, create image, remove panel, repeat 添加面板,调用包,创建图像,删除面板,重复
  • don't forget to call dispose() on the Graphics objects created by you as well 不要忘记在你创建的Graphics对象上调用dispose()
  • In worst case you can restart the JVM from a script from time to time 在最坏的情况下,您可以不时地从脚本重新启动JVM

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM