Ok my problem is simple: i make Paint application, and i would like to provide some kind of “undo” functionality. I read about undo managers and so on, but this approach seems to be difficult to understand for me so i decided to design my own. My idea is simple: since i draw on JPanel i will just save its current content just before any drawing operation is made. And undo button will just restore previous one.
The trouble is: I am unable to “restore” the saved image and place it on the JPanel. I am buffled since i have already implemented “saving” the current image on harddrive and also “opening” arbitrary image from harddrive. Both of those work perfectly fine.
Unfortunately trying the exactly the same approach for my “undo” system does not work.
Look at the code: (to simplify, i manually ‘save’ the current picture -> for testing purposes)
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();
}
Now the example of my working solution but related to woking witk files on HDD:
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");
}
}
}
}
Just in case someone is curious: updateArea function (member of extended JPanel class that represents mentioned drawingField):
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();
}
Basically the procedure is exactly the same, and working with files is ok while i cannot save and restore image when im operating on variables… What could be wrong? any ideas? When i use Undo/UndoSave buttons, absolutely nothing changes in my JPanel (drawingField)
Any help appreciated
In the code you’ve shown, you are copying your reference to the image, but both references still point at the same image object – if you perform any action which doesn’t reassign the reference (
=) it will be reflected in both references! In order to save an old version of the image, you need to copy the actual object, not just the reference.I do recommend using Java’s established undo management approach but if you want to continue with your own, these are methods you should look at: