I recently started learning the JavaFX API, after I already experience in Swing.
I noticed, that even a lot of classes were already well implemented in AWT and Swing, they were effectively re-implemented in JavaFX. This includes:
javafx.scene.paint.Color
javafx.event.ActionEvent
vs.
java.awt.Color
java.awt.event.ActionEvent
and much more, even though it could've easily require to use them. I assume that this is to:
If my assumptions are true, why didn't they include a new implementation of:
javax.swing.undo
package?
Although I understand that undo has really nothing to do with the user interface, so, it has nothing to do with Swing too. If for any reason they decided to include it in the javax.swing
package, so could they include it in JavaFX.
Why they "forgot" to implement this, is a good question. I would argue, that JavaFX is still in development (that should say everything). However, I needed this long ago and I implemented my own approach using the Command Pattern. As shown below, this is not much effort and very simple.
First you will need to create a Interface called Command, to execute some operations in your application.
public interface Command {
/**
* This is called to execute the command from implementing class.
*/
public abstract void execute();
/**
* This is called to undo last command.
*/
public abstract void undo();
}
Next you will need some class called History to save your executed commands and to undo them.
public final class History {
// ...
private static History instance = null;
private final Stack<Command> undoStack = new Stack<Command>();
// ...
public void execute(final Command cmd) {
undoStack.push(cmd);
cmd.execute();
}
public void undo() {
if (!undoStack.isEmpty()) {
Command cmd = undoStack.pop();
cmd.undo();
} else {
System.out.println("Nothing to undo.");
}
}
public static History getInstance() {
if (History.instance == null) {
synchronized (History.class) {
if (History.instance == null) {
History.instance = new History();
}
}
}
return History.instance;
}
private History() { }
}
In your FXML you then create a button for your GUI which should invoke the undo function of your application. In your FXML create a button, such as the following one:
<Button fx:id="btnUndo" font="$x2" onAction="#onUndo" prefWidth="75.0"
text="Undo" textAlignment="CENTER" underline="false">
<tooltip>
<Tooltip text="Undo last command" textAlignment="JUSTIFY" />
</tooltip>
<HBox.margin>
<Insets left="5.0" right="5.0" fx:id="x1" />
</HBox.margin>
</Button>
In your controller class you reference the button from your FXML.
public class Controller {
// ...
@FXML private Button btnUndo;
// ...
@FXML
public void onUndo(ActionEvent event)
{
History.getInstance().undo();
}
}
As you can see, the best thing is that the History class is a Singleton. So you can access the class from everywhere.
Inherit from Command interface to implement a new command. Use some buttons or similar GUI elements for new functionality and execute the custom command using your history.
// You can give arguments to command constructor if you like
Command someCmd = new SomeCommand();
History.getInstance().execute(someCmd); // Saved to history; now you're able to undo using button
With this approach you will be able to undo your operation. It is also possible to implement some redo functionality. For that just add a redo button in FXML and the appropriate method in History class and Command interface.
For more information on the command pattern, have a look here.
Happy Coding!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With