我们在JavaFX中创建了一个小型绘画应用程序。出现了一个新的要求,即我们必须警告用户,他做了一些尚未持久的更改并询问他,用户是否愿意在关闭之前先保存。
示例快照:
不幸的是,有很多不同的节点,节点可以通过多种方式进行更改,例如Polygon点可以移动。可以拖动节点本身。它们可以旋转等等。因此,在为一个Node对象的每个可能的更改触发一个极好的事件之前,我想问一下,如果有人可能知道如何简化这种方法。我很好奇,如果有任何监听器,我可以在JavaFX的场景图中听取canvas对象的任何更改。
特别是因为我只是想知道是否有任何改变,而不是真的需要知道具体的变化。
此外,我也不希望得到每个单独的事件,比如一个简单的选择,这会导致在所选节点周围显示边框(如图中所示),这并不意味着用户具有在离开之前保存他的申请。
有人有想法吗?或者我真的需要为节点中的每一次更改触发事件吗?
答案 0 :(得分:6)
我认为你正在以错误的方式解决这个问题。屏幕上显示的节点应该只是底层模型的直观表示。你真正需要知道的是底层模型已经改变了。
例如,如果您正在编写文本编辑器,则屏幕上显示的文本将由某种模型支持。我们假设模型是String
。您不需要检查屏幕上显示的任何文本节点是否已更改,您只需要将原始字符串数据与当前字符串数据进行比较,以确定是否需要提示用户保存。
答案 1 :(得分:2)
本杰明的答案可能是最好的答案:您应该使用基础模型,该模型可以轻松检查相关状态是否发生了变化。在开发应用程序的某个时刻,您将会发现这是正确的做事方式。好像你已经达到了这一点。
但是,如果你想延迟对应用程序的不可避免的重新设计(当你达到这一点时让它变得更加痛苦;)),这是你可能考虑的另一种方法。
显然,你有某种Pane
持有被绘制的物体。用户必须创建这些对象,并在某些时候将它们添加到窗格中。只需创建一个处理该添加的方法,并在执行时注册具有感兴趣属性的失效侦听器。结构看起来像这样:
private final ReadOnlyBooleanWrapper unsavedChanges =
new ReadOnlyBooleanWrapper(this, "unsavedChanged", false);
private final ChangeListener<Object> unsavedChangeListener =
(obs, oldValue, newValue) -> unsavedChanges.set(true);
private Pane drawingPane ;
// ...
Button saveButton = new Button("Save");
saveButton.disableProperty().bind(unsavedChanges.not());
// ...
@SafeVarArgs
private final <T extends Node> void addNodeToDrawingPane(
T node, Function<T, ObservableValue<?>>... properties) {
Stream.of(properties).forEach(
property -> property.apply(node).addListener(unsavedChangeListener));
drawingPane.getChildren().add(node);
}
现在你可以做像
这样的事情 Rectangle rect = new Rectangle();
addNodeToDrawingPane(rect,
Rectangle::xProperty, Rectangle::yProperty,
Rectangle::widthProperty, Rectangle::heightProperty);
和
Text text = new Text();
addNodeToDrawingPane(text,
Text::xProperty, Text::yProperty, Text::textProperty);
即。您只需指定添加新节点时要观察的属性。您可以创建一个删除侦听器的remove方法。在您已经拥有的内容之上的额外代码量是非常小的,因为(可能,我没有看到您的代码)是重构。
同样,你应该有一个单独的视图模型,等等。我想发布这个来表明@kleopatra对问题的第一个评论(“监听相关状态的失效”)并不一定涉及很多工作如果你以正确的方式接近它。起初,我认为这种方法与@Tomas Mikula提及撤消/重做功能不相容,但你甚至可以使用这种方法作为基础。