当前位置: 首页 > 知识库问答 >
问题:

如何侦听特定节点对JavaFX场景图的可见更改

湛钊
2023-03-14

我们在JavaFX中创建了一个小型绘画应用程序。出现了一个新要求,我们必须警告用户,他做了更改,这些更改尚未持久化,并询问他,用户是否想在关闭前先保存。

快照示例:

不幸的是,有很多不同的节点,节点可以通过多种方式进行更改,例如多边形点可以移动。节点本身可以拖动。它们可以旋转等等。因此,在为Node对象对画布的每一次可能的更改触发无数事件之前,我想问一下,是否有人知道如何简化这种方法。我很好奇,如果有听众,我可以在JavaFX的场景图中收听画布对象的任何更改。

特别是因为我只想知道是否有什么变化,而不是真的需要知道具体的变化。

此外,我也不想得到每一个事件,比如一个简单的选择,它会导致在所选节点周围显示边框(如图像上所示),这并不意味着用户必须保存他的应用程序离开之前。

有人有想法吗?或者我真的需要为节点中的每个更改触发事件吗?

共有2个答案

徐洛华
2023-03-14

Benjamin的答案可能是这里最好的:您应该使用一个底层模型,该模型可以很容易地检查相关状态是否发生了变化。在应用程序开发的某个阶段,您会意识到这是正确的操作方式。看来你已经到了那一步。

然而,如果您想进一步推迟不可避免的应用程序重新设计(并在达到这一点时使其更加痛苦;),这是您可以考虑的另一种方法。

显然,您有一种窗格,它保存着正在绘制的对象。用户必须正在创建这些对象,而您正在某个时候将它们添加到窗格中。只需创建一个处理该添加的方法,并使用您感兴趣的属性注册一个无效侦听器。结构将如下所示:

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

即。您只需指定添加新节点时要观察的属性。您可以创建一个也删除侦听器的删除方法。在您已经拥有的代码之上的额外代码量非常少,因为(可能,我还没有看到您的代码)是重构。

同样,你真的应该有一个单独的视图模型,等等。我想发布这篇文章,以表明@kleopatra对这个问题的第一条评论(“倾听相关州的无效性”),如果你以正确的方式处理它,不一定需要做很多工作。起初,我认为这种方法与@Tomas Mikula提到的撤消/重做功能不兼容,但您甚至可以使用这种方法作为基础。

丌官承
2023-03-14

我认为你处理这个问题的方式不对。屏幕上显示的节点应该只是底层模型的视觉表示。您真正需要知道的是,底层模型已经更改。

例如,如果您正在编写文本编辑器,屏幕上显示的文本将由某种模型支持。让我们假设模型是一个字符串。您无需检查屏幕上显示的任何文本节点是否已更改,只需将原始字符串数据与当前字符串数据进行比较,以确定是否需要提示用户保存。

 类似资料:
  • 问题内容: 我有一个prefHeight = 70 //没有prefWidth或任何宽度的HBox … 我也有一个prefWidth = 50 //没有prefHeight或任何高度的窗格… 我只想使用某些循环将窗格的多个实例添加到HBox。 当我在循环主体中添加(pane)时,出现以下错误。 我需要找到克隆窗格的方法(因为它按值传递)。有人可以帮我吗?(对我来说,拍摄快照不起作用,因为未使用父级

  • 在public void start(Stage primaryStage)中程序开始时,我制作了A的对象并将其传递给primary Stage,然后在每个类中我更改它,并且它工作得很好。但我对此没有什么疑问: 这是一个正确的方法吗? 有没有其他方法可以在保留类的同时完成它,或者我应该只在主类中完成所有操作? 传递场景然后更改根节点是否更好? 对不起,如果我问得有点多了,但我读了很多关于它仍然没有

  • 这可能有点复杂,但请忍受我。 我用SceneBuilder构建了3个场景。第一个(“主”)我用作为父场景。此场景包含1个< code>AnchorPane,其中包含一个< code>TabPane和一个< code>ToolBar,其中包含3个< code >按钮(“上一个”、“下一个”和“关闭”)。 第二个场景(“PersonaDetails”)包含一个,一个以及许多(我将其用作字段标签)几个和

  • }`我正在计划在同一舞台上使不同的部分成为自己的场景。如果有任何帮助,我将不胜感激。我正在使用NetBeans8.2。

  • /*****@作者Ahmad*/公共类NewJFrame扩展javax.swing.jFrame{ }

  • 我是JavaFX的新手。我试图编程一个简单的图形用户界面,但我面临着那些可能相关的问题。我用文件选择器设置文件,并想做相当基本的操作: 保存最后使用的文件夹 在VBox中写入选中文件的名称 这是我的代码(编译): 我无法刷新节点以设置当前初始目录或在VBox上显示collecName。我试图通过重新加载对象或调整窗口大小来重新生成它们,但没有任何效果。当我在控制台上打印变量时,我看到它们发生了变化