首页 > 编程语言 >JavaFX:实现撤销(undo)、重做(redo)功能

JavaFX:实现撤销(undo)、重做(redo)功能

时间:2023-01-08 15:12:11浏览次数:42  
标签:undoManager JavaFX undo new UndoManager redo public

撤销和重做功能在很多软件都是非常普遍的,这里记录一下JavaFX实现撤销和重做功能的一种方案:

1. 接口定义

对于所有能执行撤销和重做的动作定义统一的接口:

public interface Undo {
    void execute();
    void undo();
    void redo();
}

2. UndoManager

要实现撤销(undo)和重做(redo),需要一个UndoManager来管理所有Undo和Redo,这个UndoManager是整个撤销和重做的核心,下面是具体的实现代码:

public class UndoManager {

    private static final UndoManager instance = new UndoManager(30);
    public static UndoManager getInstance() {
        return instance;
    }

    private final int maxSize;
    private final List<Undo> undoStack = new ArrayList<>();
    private final List<Undo> redoStack = new ArrayList<>();

    public UndoManager(int maxSize) {
        this.maxSize = maxSize;
    }

    public void push(Undo undo) {
        undo.execute();
        undoStack.add(0, undo);
        if (undoStack.size() > maxSize) {
            undoStack.remove(undoStack.size() - 1);
        }
        redoStack.clear();
    }

    public void clear() {
        undoStack.clear();
        redoStack.clear();
    }


    public boolean canUndo() {
        return !undoStack.isEmpty();
    }

    public void undo() {
        final Undo undo = undoStack.get(0);
        undo.undo();
        undoStack.remove(0);
        redoStack.add(0, undo);
    }

    public boolean canRedo() {
        return !redoStack.isEmpty();
    }

    public void redo() {
        final Undo undo = redoStack.get(0);
        undo.redo();
        redoStack.remove(0);
        undoStack.add(0, undo);
    }
}

3. 使用UndoManager

UndoManager的使用非常简单,直接通过UndoManager.getInstance()获取实例即可,默认情况下支持撤销的次数为30。

下面是一个使用例子:

public class Sample02 extends Application {

    @Override
    public void start(Stage stage) {
        UndoManager undoManager = UndoManager.getInstance();

        StackPane root = new StackPane();

        VBox container = new VBox();
        container.setSpacing(10);
        container.setAlignment(Pos.CENTER);
        root.getChildren().add(container);

        Button btn = new Button("新增文本");
        AtomicInteger inc = new AtomicInteger(0);
        btn.setOnMouseClicked(event -> undoManager.push(new TextUndo(container, new Label("米虫2022" + inc.incrementAndGet()))));

        Button undo = new Button("撤销(undo)");
        undo.setOnMouseClicked(event -> {
            if (undoManager.canUndo()) {
                undoManager.undo();
            }
        });

        Button redo = new Button("重做(redo)");
        redo.setOnMouseClicked(event -> {
            if (undoManager.canRedo()) {
                undoManager.redo();
            }
        });

        container.getChildren().addAll(btn, undo, redo);

        stage.setTitle("撤销 + 重做");
        stage.setWidth(320);
        stage.setHeight(480);
        stage.setScene(new Scene(root));
        stage.getIcons().clear();
        stage.getIcons().add(new Image("logo.jpg"));
        stage.show();
    }
}

效果如下:

4. 监听

可以进一步完善UndoManager对外暴露变更属性,外部通过监听变更,跟无法undo或者redo时禁用相应的功能。

调整代码实现如下:

Button undo = new Button("撤销(undo)");
undo.setDisable(true);
undo.setOnMouseClicked(event -> {
    if (undoManager.canUndo()) {
        undoManager.undo();
    }
});

Button redo = new Button("重做(redo)");
redo.setDisable(true);
redo.setOnMouseClicked(event -> {
    if (undoManager.canRedo()) {
        undoManager.redo();
    }
});

undoManager.revisionProperty().addListener((ob, ov, nv) -> {
    undo.setDisable(!undoManager.canUndo());
    redo.setDisable(!undoManager.canRedo());
});

效果如下:

标签:undoManager,JavaFX,undo,new,UndoManager,redo,public
From: https://www.cnblogs.com/michong2022/p/17034694.html

相关文章

  • JavaFX:实现滚动 + 缩放联动
    JavaFX要实现滚动可以使用ScrollPane,要实现缩放可以通过调用setScaleX和setScaleY、setScaleZ,如果需要实现滚动+缩放联动,那么需要一点点小技巧,这里记录一下。1.实现滚......
  • JavaFX:构建JavaFX的IoC,实现Bean管理,自由注入Contoller需要的Bean
    习惯了使用Spring的IoC开发JavaEE应用之后,总想着在JavaFX开发中使用IoC管理应用中的单例对象,这里记录一下构建JavaFX.IoC实现Bean管理和依赖注入的过程。1.IoC.需求实际......
  • oracle在线增加redo日志组成员
    文档课题:oracle在线增加redo日志组成员.数据库:oracle11.2.0.41、相关知识oracle通过redo保证数据库事务可以被重演,从而使得在发生故障之后,数据可以被恢复.redo对于oracle数......
  • 【¡Hola mundo!】测试文章和数模经验的笔记
    这是一篇测试文章没什么可说的,所以就放一篇数模经验的笔记8萨特沙盐同学的意识流数学建模经验分享————连续型问题建模与论文撰写提醒:建议同学们在参加之前对数学......
  • javaFX中Label如何设置居中
    Labellabel=newLabel("居中");HBoxhBox=newHBox();hBox.getChildren().addAll(label);hBox.setPrefHeight(35);hBox.setPrefWidth(410);hBox.setLayoutX(125);//hBo......
  • javaFX中Label如何设置居中
    Labellabel=newLabel("居中");HBoxhBox=newHBox();hBox.getChildren().addAll(label);hBox.setPrefHeight(35);hBox.setPrefWidth(410);hBox.setLayoutX(125);//hBo......
  • javaFX中Label如何设置居中
    Labellabel=newLabel("居中");HBoxhBox=newHBox();hBox.getChildren().addAll(label);hBox.setPrefHeight(35);hBox.setPrefWidth(410);hBox.setLayoutX(125);//hBo......
  • 数据库日志——binlog、redo log、undo log扫盲
    日志是数据库中比较重要的组成部分,很多核心的功能必须依靠日志才能完成。该篇文章简要介绍了binlog、redolog与undolog,能够在一定程度上拓宽对mysql日志的整体认识。......
  • 如何定位那些SQL产生了大量的redo日志
    在ORACLE数据库的管理、维护过程中,偶尔会遇到归档日志暴增的情况,也就是说一些SQL语句产生了大量的redolog,那么如何跟踪、定位哪些SQL语句生成了大量的redolog日志呢?下面......
  • Cf 455A [Boredom]
    Cf455ABoredom题意:给出\(n\)个数字,从中选一个\(a_k\)删除,\(a_k\)为你获得的值,删除\(a_k\)后,如果数组里面有\(a_{k+1},a_{k-1}\)也会被删除,求获得值最大为......