Jump to content

Implementing Undo/Redo


Recommended Posts

So I found Fabiola's example here and I really like it. However, I would like to make something a bit more generic, where the input item is an object rather than a cluster. The different objects that represented undoable operations would have a must override "undo" and "redo" method which would handle how changes to that object are undone or redone. Problem is, I have to start inheriting everything from some base "undo/redo" class in order to force must overrides. I feel I am skirting around the edge of why interfaces are valuable in JAVA. I could just implement an undoable and redoable interface for my GUI objects I want to have undo redo operations for. Has anyone implemented this in a bit more generic way that ports from app to app? Fabiola, if you're reading and you can voice your opinion or any changes you've made since that code was posted I'd appreciate it!

 

Thanks. 

Link to comment

I have, sort of But only for the UI (not for things like charts etc, but I suppose I could have).

 

I used the same code as I use for config dialogues (it just iterates over UI controls), and kept a history of changes in a DB. You then just query the DB. You can go back, forward and, if you put a little bit of additional info in (like a short description), you can list the last (say) 10 changes in a menu and jump straight to them unwinding the list.

 

By linking the entries to the control label, it works transparently and is not application dependent. I also attached events to all controls that I was interested in so I didn't have to write specific queries to enter them into the DB.

Link to comment

So I have been contemplating and am going to think "out loud" here. I think this is basically what you are saying Shaun, but I'm going to reiterate in my own words. I am talking solely about value change events here. The stuff with the graphs charts etc is nice, but I don't believe state changes to a graph are captured by the event structure, so you'd have to be polling for any property changes. Man, it would be nice if changing properties fired event...anyways, I digress.  My thought is have an "Undoable" object with must override undo and redo methods. Then, this base class can hold a reference to the control that was changed. There can be child classes for string undo, int undo, etc all the common data types. That would allow for a programmer to implement app specific undo/redo methods for things like clusters and arrays of clusters and so on, but also reuse the classes already written for string control changes, numeric changes etc. These "undoable" child classes would simply hold the previous data. So, when an undo happens, they have the control ref and the previous value and can set the UI control to that. One issue I can see is determining which undoable child class to instantiate based on the control type which had its value changed. I guess I could have some sort of "undo type factory" or something along those lines. Again, just thinking outloud.

 

Would this work? 

Edited by for(imstuck)
Link to comment

I have a very simple written an example app taken from the Head First's design Pattern book.

Look at the Command patterns here:

https://decibel.ni.com/content/message/35117#35117

 

But basically you have to (not maybe have to, but if you want it scalable and reusable) use the Command Design pattern, (and together with the memento pattern to get a very scalable solution).

This is just one link that descripbes it.

http://www.codeproject.com/Articles/33384/Multilevel-Undo-and-Redo-Implementation-in-C-Part

 

Cheers,

Mike

Link to comment

I've done this using bacisally the memento pattern.

 

I create an Class for my program (which derives from a base Memento class) which then stores ALL data needed to properly enumerate the program at that time.  Since I'm dealing mainly with UI representation of incoming data, this is do-able with finite effort.

 

I then have my undo / redo handler which receives and spits out objects of the Memento Type which can then be simply inserted (when a new step could be undone) or retrieved (when undoing or re-doing).

 

I've found this to work really simply given the initial assumption that the objects you are "storing" completely represent the VI state at that point in time.

 

Shane.

 

PS Yeah, the stored objects could each represent sub-states of a VI but given the number of VIs I have to implement and the finite time my days offer, this is by far the quickest solution I could come up with and it's complexity is not overwhelming.

Link to comment
I've done this using bacisally the memento pattern.

 

I create an Class for my program (which derives from a base Memento class) which then stores ALL data needed to properly enumerate the program at that time.  

 

Just curious, have you run into an issue with memory, storing all that state data for a single change?

Link to comment
Just curious, have you run into an issue with memory, storing all that state data for a single change?

 

No, I don't store THAT much.  Each undo or redo is a coupld of kb at most.

 

I generally sculpt my UI to have a single (for smaller VIs) state for updating the display which simply takes this data and, well, updates the display.  The actual DATA is coming from elsewhere, I'm not storing that because as soon as I store it it's out of date.  A lot of my state data is references (which are essentially unchanging and COULD be stored elsewhere) and simply visibility settings and so on.  Typical UI stuff.  I'm not writing a word processor.

 

Shane.

  • Like 1
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.