Почему JavaFX не включает средство отмены

Недавно я начал изучать API JavaFX после того, как я уже знаком с Swing.

Я заметил, что даже многие классы уже были хорошо реализованы в AWT и Swing, они были эффективно реализованы в JavaFX. Это включает в себя:

javafx.scene.paint.Color
javafx.event.ActionEvent

против.

java.awt.Color
java.awt.event.ActionEvent

и многое другое, даже если он мог легко потребовать их использования. Я предполагаю, что это:

  • Разделить JavaFX наиболее возможно, из других библиотек (поэтому новые разработчики не должны даже знать о своем существовании..., ОК).
  • Использование лямбда-выражений Java 8.
  • Использовать общие типы и типы перечислений Java 5.
  • Дизайн с учетом FXML.
  • Привязки... версия магии JavaFX.

Если мои предположения верны, почему они не включили новую реализацию:

javax.swing.undo

пакет?

Хотя я понимаю, что отмена не имеет никакого отношения к пользовательскому интерфейсу, поэтому она не имеет ничего общего с Swing. Если по какой-либо причине они решили включить его в пакет javax.swing, поэтому они могут включить его в JavaFX.

Ответ 1

Почему они "забыли" реализовать это, это хороший вопрос. Я бы сказал, что JavaFX все еще находится в разработке (это должно сказать все). Однако мне это было нужно очень давно, и я применил свой собственный подход, используя Command Pattern. Как показано ниже, это не так много усилий и очень просто.

Сначала вам нужно создать интерфейс под названием "Command", чтобы выполнить некоторые операции в вашем приложении.

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();
}

Далее вам понадобится какой-то класс с именем History, чтобы сохранить выполненные команды и отменить их.

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() { }
}

В своем FXML вы создаете кнопку для своего графического интерфейса, которая должна вызывать отмену функции вашего приложения. В FXML создайте кнопку, например следующую:

<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>

В вашем классе контроллера вы ссылаетесь на кнопку с вашего FXML.

public class Controller {
    // ...
    @FXML private Button btnUndo;
    // ...

    @FXML
    public void onUndo(ActionEvent event)
    {
        History.getInstance().undo();
    }
}

Как вы можете видеть, лучше всего, что класс History - это Singleton. Таким образом, вы можете получить доступ к классу везде.

Наследовать из интерфейса Command для реализации новой команды. Используйте некоторые кнопки или аналогичные элементы GUI для новых функций и выполните пользовательскую команду, используя свою историю.

// 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

При таком подходе вы сможете отменить свою операцию. Также возможно реализовать некоторые функции повтора. Для этого просто добавьте кнопку повтора в FXML и соответствующий метод в классе History и Command.

Для получения дополнительной информации о шаблоне команд посмотрите здесь.

Счастливое кодирование!