2013-05-16 34 views
10

绑定到自身包装在属性中的对象的属性看起来像是在典型应用程序中做了很多事情,是否有更好的方式在JavaFX中执行此操作我在下面做?绑定到可切换对象的JavaFX属性

一些更多的细节解释:我想在JavaFX 2.2中制作GUI,以管理一些项目。我创建了一个小例子来测试所有项目都是人的东西。这组人以自定义的方式显示(不是列表或树,但我认为这不重要),我可以选择一个。

在侧面板中,我可以编辑当前选定的人员。更新在人员集合中立即可见,并且当我选择另一个人时,编辑面板将被更新。

JavaFX的双向绑定似乎是完美的。我现在有这样的FX:在“人编辑”面板的控制器:

public class PersonEditor implements ChangeListener<Person> { 
    @FXML private TextField nameField; 
    @FXML private TextField ageField; 
    @FXML private TextField heightField; 

    public void setSelection(ObjectProperty<Person> selectedPersonProperty) { 
     selectedPersonProperty.addListener(this); 
    } 

    @Override 
    public void changed(ObservableValue<? extends Person> observable, Person oldVal, Person newVal) { 
     if (oldVal != null) { 
      nameField.textProperty().unbindBidirectional(oldVal.nameProperty()); 
      ageField.textProperty().unbindBidirectional(oldVal.ageProperty()); 
      heightField.textProperty().unbindBidirectional(oldVal.heightProperty()); 
     } 
     if (newVal != null) { 
      nameField.textProperty().bindBidirectional(newVal.nameProperty()); 
      ageField.textProperty().bindBidirectional(newVal.ageProperty()); 
      heightField.textProperty().bindBidirectional(newVal.heightProperty()); 
     } 
    } 
} 

我想知道是否有更好的方式,或许还有JavaFX中做结合,可以改变一个对象的属性?我不喜欢我必须手动取消绑定所有属性的事实,它感觉像重复的代码。 或者这可以在JavaFx中简单吗?

回答

2

看来这不是在JavaFX中可以更优雅地完成的事情。绑定和解除绑定似乎是最干净的方式。

我确实实现了一种方法来做到这一点。不知道我最终是否最终会使用它(因为它只是用难以阅读的代码来替代代码重复)。但它有效,它是我自己问题的答案,所以我在这里添加了它。

新PersonEditor类:

public class PersonEditor implements Initializable { 
    private SelectedObjectPropertyBinder<Person> selectedObjectPropertyBinder = 
      new SelectedObjectPropertyBinder<Person>(); 

    @FXML private TextField nameField; 
    @FXML private TextField ageField; 
    @FXML private TextField heightField; 

    @Override 
    public void initialize(URL url, ResourceBundle rb) { 
     selectedObjectPropertyBinder.getBinders().add(
      new ObjectPropertyBindHelper<Person>(nameField.textProperty()) { 
       @Override public Property objectProperty(Person p) 
       { return p.nameProperty(); } 
     }); 
     selectedObjectPropertyBinder.getBinders().add(
      new ObjectPropertyBindHelper<Person>(ageField.textProperty()) { 
       @Override public Property objectProperty(Person p) 
       { return p.ageProperty(); } 
     }); 
     selectedObjectPropertyBinder.getBinders().add(
      new ObjectPropertyBindHelper<Person>(heightField.textProperty()) { 
       @Override public Property objectProperty(Person p) 
       { return p.heightProperty(); } 
     }); 
    } 

    public void setSelection(ObjectProperty<Person> selectedPersonProperty) { 
     selectedObjectPropertyBinder. 
      setSelectedObjectProperty(selectedPersonProperty); 
    } 
} 

辅助类:

public class SelectedObjectPropertyBinder<T> implements ChangeListener<T> { 
    private List<ObjectPropertyBindHelper<T>> binders = 
      new ArrayList<ObjectPropertyBindHelper<T>>(); 

    public void setSelectedObjectProperty(Property<T> selectionProperty) { 
     selectionProperty.addListener(this); 
    } 

    public List<ObjectPropertyBindHelper<T>> getBinders() { 
     return binders; 
    } 

    @Override 
    public void changed(ObservableValue<? extends T> observable, 
         T oldVal, T newVal) { 
     if (oldVal != null) 
      for (ObjectPropertyBindHelper b : binders) 
       b.unbindBi(oldVal); 
     if (newVal != null) 
      for (ObjectPropertyBindHelper b : binders) 
       b.bindBi(newVal); 
    } 
} 

public abstract class ObjectPropertyBindHelper<T> { 
    private Property boundProperty; 

    public ObjectPropertyBindHelper(Property boundProperty) { 
     this.boundProperty = boundProperty; 
    } 
    public void bindBi(T o) { 
     boundProperty.bindBidirectional(objectProperty(o)); 
    } 
    public void unbindBi(T o) { 
     boundProperty.unbindBidirectional(objectProperty(o)); 
    } 
    public abstract Property objectProperty(T t); 
    public Property getBoundProperty() { 
     return boundProperty; 
    } 
} 

由于scottb在他的回答中指出,束缚链接,这并不总是你想要什么呢。如果你想能够取消/提交更改,你也可以使用类似的方法来实现它(但是它可能会更难读取结果代码)。

3

就我个人而言,我没有发现您在事件处理程序中编写的代码太笨重或笨拙。这是事件处理程序通常在GUI中执行的事情,即imo。

问自己,虽然...在你的情况下真的有必要吗?

如果您必须实时更新您在一个面板中进行的编辑以反映到另一个面板中,那么您可能已经实施了最简单的解决方案。这种UI设计存在固有的困难,但它可能并不适合所有情况。如果用户需要取消他所做的编辑会怎么样?如果他改变了主意,你是否有办法回滚编辑?有时候,编辑中的实时更改是不可取的,在这种情况下,将数据模型对象绑定到UI对象可能不是一个好主意。

+0

嗯,是的,我看到你指出绑定并不总是需要的。但在这种情况下,我最终会遇到类似的情况:我通过制作2个辅助方法,1个方法“selectedPersonToFields”和1个方法“fieldsToSelectedPerson”来实现它。在这两种情况下,您都可以将字段集中的数据复制到人员属性集合(或反向)。再一次,这是两倍几乎相同的代码!不知何故,我想避免在这两种情况下。我觉得它可以更优雅。我正在寻找一些现有的JavaFX方式来做到这一点,或者一些模式或我可以实现的一些模式来做到这一点...... –