将 JPanel 保存为图像(不是文件,而是变量)

Posted

技术标签:

【中文标题】将 JPanel 保存为图像(不是文件,而是变量)【英文标题】:Saving JPanel as image (not as file, but as a variable) 【发布时间】:2012-07-16 11:40:17 【问题描述】:

好的,我的问题很简单:我制作了 Paint 应用程序,我想提供某种“撤消”功能。我阅读了有关撤消管理器等的信息,但这种方法对我来说似乎很难理解,所以我决定自己设计。我的想法很简单:因为我在 JPanel 上绘图,所以我只会在进行任何绘图操作之前保存其当前内容。而撤消按钮只会恢复上一个。

问题是:我无法“恢复”保存的图像并将其放置在 JPanel 上。我很困惑,因为我已经在硬盘驱动器上“保存”了当前图像,并从硬盘驱动器“打开”了任意图像。两者都工作得很好。

不幸的是,为我的“撤消”系统尝试完全相同的方法不起作用。

查看代码:(为了简化,我手动“保存”当前图片 -> 用于测试目的)

public class PictureEdit  //class for saving the current JPanel drawing for undo
    public BufferedImage saveBI;
    public Graphics2D saveG2D;


public void actionPerformed(ActionEvent e)  //action for "UNDO" button, not working
    //drawingField - instance of JPanel
    //pe - instance of PictureEdit class
    drawingField.setBufferedImg(drawingField.pe.saveBI);
    drawingField.updateArea(drawingField.getBufferedImg());            


public void actionPerformed(ActionEvent e)  //action for manual "save" (for undo)
    drawingField.pe.saveBI=drawingField.getBufferedImg();
    drawingField.pe.saveG2D=(Graphics2D)drawingField.getBufferedImg().getGraphics();


现在是我的工作解决方案的示例,但与硬盘上的 wok witk 文件有关:

public void actionPerformed(ActionEvent e) //Opening file from harddrive - works fine
    JFileChooser jfc = new JFileChooser();
    int selection = jfc.showOpenDialog(PaintUndo.this);
    if (selection == JFileChooser.APPROVE_OPTION)                
        try 
           drawingField.setBufferedImg(ImageIO.read(jfc.getSelectedFile()));
           drawingField.updateArea(drawingField.getBufferedImg());

         catch (IOException ex) 
           Logger.getLogger(PaintUndo.class.getName()).log(Level.SEVERE, null, ex);
           JOptionPane.showMessageDialog(PaintUndo.this, "Could not open file");
        
                     



public void actionPerformed(ActionEvent e)  //Saving to harddrive - works fine
     int n = JOptionPane.showConfirmDialog(PaintUndo.this, "Are you sure you want to save?", "Saving image...", JOptionPane.OK_CANCEL_OPTION);
     if (n == JOptionPane.YES_OPTION)
        JFileChooser jfc = new JFileChooser();
        int nn = jfc.showSaveDialog(PaintUndo.this);
        if (nn == JFileChooser.APPROVE_OPTION)                       
           File saveFile = new File(jfc.getSelectedFile()+".bmp");
           try 
              ImageIO.write(drawingField.getBufferedImg(), "bmp", saveFile);
            catch (IOException ex) 
              Logger.getLogger(PaintUndo.class.getName()).log(Level.SEVERE, null, ex);
              JOptionPane.showMessageDialog(PaintUndo.this, "Error while saving file");
                                  
        
     
 

以防万一有人好奇:updateArea 函数(代表提到的 drawingField 的扩展 JPanel 类的成员):

public void updateArea(BufferedImage img) //it is just resizing the current picture (if necessary) and then assigns the new Graphics.
    area.height=img.getHeight();
    area.width=img.getWidth();
    this.setPreferredSize(area);
    g2d = (Graphics2D)this.getGraphics();

基本上这个过程是完全一样的,处理文件没问题,而当我对变量进行操作时,我无法保存和恢复图像......可能出了什么问题?有任何想法吗?当我使用 Undo/UndoSave 按钮时,我的 JPanel 中绝对没有任何变化 (drawingField)

任何帮助表示赞赏

【问题讨论】:

撤消功能取决于您的绘图方式。你在画简单的形状吗?还是绘制任意像素? 1) 发布SSCCE,而不是发布我们必须进行疯狂猜测的点点滴滴 2) 虽然您的方法是原创的,但它会非常消耗内存,并且在每次操作时,您将不得不重新绘制一个不那么便宜的新 BufferedImage。 嗯,是的,我正在绘制简单的形状,如点、线、矩形、椭圆形。除此之外,我正在旋转/翻转图像。关于 SSCCE:pastebin.com/0QY4uwHG(我将代码最小化到最低限度以使其可运行 -> 排除了椭圆/矩形和翻转/旋转的绘图)。关于我的方法,我不认为UndoManager 在内存方面“更便宜”——但我在这里可能错了。尽管如此,试图理解 undomanager 对我来说有点痛苦,所以我决定自己去。 UndoManager 是否非常好并且经过优化,因此它会比我的解决方案更快? 【参考方案1】:

在您显示的代码中,您正在复制对图像的引用,但两个引用仍然指向同一个图像对象 - 如果您执行任何不重新分配引用 (=) 的操作,它将反映在两个引用中!为了保存旧版本的图像,您需要复制实际对象,而不仅仅是引用。

我确实建议使用 Java 已建立的撤消管理方法,但如果您想继续使用自己的方法,您应该查看以下方法:

//BufferedImage image;
Raster raster = image.getData(); // save
image.setData(raster); // restore

【讨论】:

好的,这可以正常工作,但是我会尝试以某种方式实现 UndoManager。感谢您的支持。

以上是关于将 JPanel 保存为图像(不是文件,而是变量)的主要内容,如果未能解决你的问题,请参考以下文章

内存中的 OpenCV jpeg 格式图像

将 JPanel 转换为图像

将 Java 2d 图形图像保存为 .png 文件

在 JFrame 中将图像绘制到 JPanel

将图像保存到内存

将图像设置为 JPanel 背景的最简单方法