【问题标题】:javafx gui update strategy with bidirectionalbinding具有双向绑定的 javafx gui 更新策略
【发布时间】:2014-12-12 01:18:10
【问题描述】:


我正在为与配置类的变量链接的 gui 元素(在我的情况下为 javafx,TextField)寻找适当的更新策略。 必须满足这些规则:
1) 如果我在配置类中设置变量,则 gui 元素(文本字段)需要刷新
2) 如果我更改文本字段,则配置类中的变量需要刷新
3) 当且仅当配置类中的变量发生更改时,由于文本字段更改,必须采取一些措施。
4) 如果我更改配置中的变量,我不希望执行该操作(即通知侦听器)。

假设是这样的:

Gui.java
public TextField textField = new TextField();



Config.java
public StringProperty stringProperty = new StringProperty();
stringProperty .addListener(new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> arg0, String arg1, String arg2) {
            System.out.println("config string changed").

        }
    });


  public void update(){
    // now this is causing the problem because the listener
    // will know about this set() obviously
    stringProperty.set("bad idea");
  }


Controller.java
Gui gui = new Gui();
Config config = new Config();

// setup connection between gui element and config
gui.textField.textProperty().bindBidirectional(config.stringProperty);

我知道我可以在设置值之前删除 changeListener 然后再次添加它,但我想知道是否有适当的解决方案来解决此类问题。

编辑: 实际上我需要知道的是:是因为绑定还是因为 set() 而调用了 changed()。如果可以的话,我的问题就迎刃而解了。

谢谢!

干杯!

【问题讨论】:

  • 你能澄清一下(3)吗?您是否希望在每次更改文本字段中的文本时(即每次按键等),或仅在用户“提交”更改时(例如通过按 Enter)执行此操作?
  • 我想得到每一个改变。这与双向绑定非常有效。我唯一担心的是 set() 会“触发”听众。我编辑了代码以阐明可以从其他一些类调用更新方法。

标签: user-interface binding javafx


【解决方案1】:

您始终可以使用一对侦听器模拟双向绑定:

StringProperty a = new SimpleStringProperty("");
StringProperty b = new SimpleStringProperty("");

a.addListener((obs, oldValue, newValue) -> {
    b.set(newValue);
});

b.addListener((obs, oldValue, newValue) -> {
    a.set(newValue);
});

属性类中的set 方法足够聪明,可以在通知任何侦听器之前检查值是否真的被改变了,所以你不会在这里遇到无限递归的问题(尽管你需要非常小心,如果您可以使用浮点类型执行此操作)。

这对您有帮助,因为“其他”属性的状态可以帮助确定您如何访问侦听器代码。考虑调用

a.set("update");

在这种情况下,我们有:

  1. ab 都是空字符串
  2. 我们致电a.set("update")
  3. a 将其值更改为 "update"b 仍然是一个空字符串
  4. 由于a 已更改,它的侦听器使用oldValue=""newValue=a.get()="update" 调用。请注意,b.get() 返回的值与newValue 不同
  5. a的监听器调用b.set("update"),所以现在ab都是"update"
  6. 由于b 已更改,其侦听器使用oldValue=""newValue="update" 调用。请注意,在这种情况下,a.get() 返回的值与newValue 相同。
  7. b 的侦听器调用 a.set("update"),这是一个无操作(因为 a 已经具有该值)。

所以现在你可以编写如下监听器:

a.addListener((obs, oldValue, newValue) -> {
    if (b.get().equals(newValue)) {
        // change to a occurred via a change to b
    } else {
        // change to a occurred via a call to a.set(...)
        b.set(newValue);
    }
});

b.addListener((obs, oldValue, newValue) -> {
    if (a.get().equals(newValue)) {
        // change to b occurred via a change to a
    } else {
        // change to b occurred via a call to b.set(...)
        a.set(newValue);
    }
});

在您的具体示例中,您可以执行以下操作:

gui.textField.textProperty().addListener((obs, oldText, newText) -> 
    config.stringProperty().set(newText));

config.stringProperty().addListener((obs, oldText, newText) -> {
    if (gui.textField.getText().equals(newText)) {
        System.out.println("Text field was changed to: "+newText);
    } else {
        gui.textField.setText(newText);
    }
});

【讨论】:

  • 您好 James_D,感谢您的建议,但是他们将迫使我在包含 gui 元素的类中实现 processUserTextUpdate() 方法。我更喜欢一个解决方案,我可以将我的侦听器放在配置属性上,因为它们是中心点,而 gui 组件可以位于不同的类中。我认为解决方案应该朝着当我设置 stringProperty.set() 时不应调用 changelistener 的方向发展。
  • 其实我需要知道的;是由于绑定或由于 set() 而调用的 change()。如果这是可能的,我的问题就解决了。
  • 更改答案以澄清。
  • 不过,问题是我需要知道配置类中的每个 gui 元素。但是,我确实在某种程度上知道它,因为无论如何我都需要绑定元素。
猜你喜欢
  • 2011-01-19
  • 2015-03-01
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 2011-01-08
  • 2015-01-19
  • 2017-04-22
  • 2014-01-09
相关资源
最近更新 更多