0
votes

I want to create "undo" and "redo" buttons using stacks (not swing).

When "undo" is clicked, Textfields, Lists and everything need to be undone/redone. I know I have to use pop, push, etc. But what do I put in the stacks? Textfield values? List contents?

Example:

  • I register a student in a school.
    • Student infos in textfields are changed
    • The list of students contains the new student

How do I reset these?

And is there a way to just stock the current state of the project's data in the stack?

1
You might need to clarify a little. What exactly do you need to undo? The student registration, or what people write in the textfields? Where do you store the registered student? - cgarciahdez
i need to undo every thing. the student objects are stored in a list. the list and the textfields need to be undone, just like a ctr+z, if there was something else before , it needs to show up instead of a blank txt field - Crichou Crichou
I updated you text and reduced it to make it easier to read. - slartidan

1 Answers

3
votes

Hopefully, I got you right, since I do not really understand what you mean by "using stacks (not swing)". A Stack is a data structure and Swing is a UI framework. So those have basically nothing to do with each other.

Implementing undo/redo is typically done by using one of the following approaches. Which one you should use depends on your desired undo/redo behavior.

Undo/redo using the Command Pattern.

Implementing this approach would look something like this:

public interface ICommand {
    void do();
    void undo();
}

public class StudentSaveCommand implements ICommand {

    public StudentSaveCommand(Student student) { ... }
    [...]
}

In the do() implementation of the StudentSaveCommand class you implement the action which should be taken to actually save the given student, e.g. inserting the data into the database, saving to a file or simply adding it to a list. In the undo() implementation you implement the action to revert the do() implementation, e.g. deleting from the database, deleting the file or removing it from the list.

To finally implement the undo/redo feature using Stacks you would do something like this:

public void btnSaveStudentClickHandler() {
    ICommand c = new IStudentSaveCommand(theStudentFromGUI);
    c.do();
    _redoStack.clear();
    _undoStack.push(c);
}

public void btnUndoClickHandler() {
    ICommand undoCommand = _undoStack.pop();
    undoCommand.undo();
    _redoStack.push(undoCommand); 
}

public void btnRedoClickHandler() {
    ICommand redoCommand = _redoStack.pop();
    redoCommand.do();
    _undoStack.push(redoCommand);
}

To easily reflect the changes on your model to your GUI I would implement/use some sort of data binding. As you can see, this approach is not that appropriate to implement undo/redo on a very fine-grained level, e.g. changing a student's name in a textbox. Here comes the second approach into play.

Undo/redo using Memento Pattern.

Using this pattern allows you to save and restore states of an object, e.g. a Student. The implementation for an undo/redo feature using this pattern and Stacks the code would probably look something like this:

public void txtStudentNameLostFocusHandler() {
    Memento sm = student.getSavedState();
    _redoStack.clear();
    _undoStack.push(sm);
}

public void btnUndoClickHandler() {
    Memento m = _undoStack.pop();
    student.restoreSavedState(m);
    _redoStack.push(m);
}

// [...] Redo implementation straight-forward

To reflect the changes which were made to the Student object I also would prefer data binding or implement a method like the following which must be called after an undo/redo action:

public void updateStudentGUI(Student student) {
    txtName.setText(student.getName());
    [...]
}

To have the advantages of both approaches in your undo/redo implementation you also can combine those. However, the best approach depends strongly on the specification, respectively what you really want to achieve.