POJO和JavaFX组件之间的绑定问题

时间:2013-07-15 12:18:23

标签: java javafx bind

目前,我想要做的是使用JAXB生成的POJO将每个Java属性绑定到JavaFX组件。为此,我继续如下:

  • 我更改了JAXB的默认生成以添加 PropertyChangeSupport 以使POJO支持绑定。
  • 我创建了一种工厂,它在输入中获取一个类实例并返回一个Map,其中 key 是属性本身,与之绑定的JavaFX组件该物业的价值。
  • 返回的地图显示在JFXPanel中。

以下是我工厂的样本:

public static Map<Field, Node> createComponents(Object obj) throws NoSuchMethodException
{
        Map<Field, Node> map = new LinkedHashMap<Field, Node>();

        for (final Field field : obj.getClass().getDeclaredFields())
        {
            @SuppressWarnings("rawtypes")
            Class fieldType = field.getType();

            if (fieldType.equals(boolean.class) || (fieldType.equals(Boolean.class))) //Boolean
            {
                map.put(field, createBool(obj, field));
            }
            else if (fieldType.equals(int.class) || (fieldType.equals(Integer.class))) //Integer
            {
               map.put(field, createInt(obj, field));
            }
            else if (fieldType.equals(BigInteger.class)) //BigInteger
            {
               map.put(field, createBigInt(obj, field));
            }
            else if (fieldType.equals(long.class) || fieldType.equals(Long.class)) //Long
            {
               map.put(field, createLong(obj, field));
            }
            else if (fieldType.equals(String.class)) //String
            {
               map.put(field, createString(obj, field));

            }
            ...
        }
        return map;   
} 

public static Node createBool(Object obj, final Field field) throws NoSuchMethodException
{

      System.out.println(field.getType().getSimpleName() + " spotted");
      JavaBeanBooleanProperty boolProperty = JavaBeanBooleanPropertyBuilder.create().bean(obj).name(field.getName()).build();
      boolProperty.addListener(new ChangeListener<Boolean>() {
         @Override
         public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2)
         {
            prettyPrinter(field, arg1, arg2);
         }
      });
      CheckBox cb = new CheckBox();
      cb.setText(" : " + field.getName());
      cb.selectedProperty().bindBidirectional(boolProperty);
      return cb;

}

public static Node createInt(Object obj, final Field field) throws NoSuchMethodException
{
      System.out.println(field.getType().getSimpleName() + " spotted");
      JavaBeanIntegerProperty intProperty = JavaBeanIntegerPropertyBuilder.create().bean(obj).name(field.getName()).build();
      StringProperty s = new SimpleStringProperty();
      StringConverter sc = new IntegerStringConverter();
      Bindings.bindBidirectional(s, intProperty, sc);
      s.addListener(new ChangeListener<String>() {
         @Override
         public void changed(ObservableValue<? extends String> arg0, String arg1, String arg2)
         {
            prettyPrinter(field, arg1, arg2);
         }
      });

      TextField tf = new TextField();
      tf.textProperty().bindBidirectional(s);

      return tf;

}

所以,我遇到的问题是:在大多数情况下,当我更改时,例如,一个textField,POJO属性不会注意到。但在某些情况下,当我更改POJO中字段的顺序时,每个监听器都会注意到任何变化。

以下是使用后面的 Personne 类(当前有效)的GUI的示例

GUI Example

public class Personne
{

   private int                   taille;

   private Boolean               lol;

   private long                  pointure;

   private BigInteger            age;

   private boolean               zombified;

   private String                name;

   private PropertyChangeSupport _changeSupport = new PropertyChangeSupport(this);

   public Boolean getLol()
   {
      return this.lol;
   }

   public long getPointure()
   {
      return this.pointure;
   }

   public int getTaille()
   {
      return taille;
   }

   public boolean getZombified()
   {
      return zombified;
   }

   public BigInteger getAge()
   {
      return age;
   }

   public String getName()
   {
      return name;
   }

   public void setPointure(long pointure)
   {

      final long prev = this.pointure;
      this.pointure = pointure;
      _changeSupport.firePropertyChange("pointure", prev, pointure);
   }

   public void setTaille(int taille)
   {
      final int prev = this.taille;
      this.taille = taille;
      _changeSupport.firePropertyChange("taille", prev, taille);
   }

   public void setAge(BigInteger age)
   {
      final BigInteger prev = this.age;
      this.age = age;
      _changeSupport.firePropertyChange("age", prev, age);

   }

   public void setName(String name)
   {
      final String prev = this.name;
      this.name = name;
      _changeSupport.firePropertyChange("name", prev, name);
   }

   public void setLol(Boolean lol)
   {
      final Boolean prev = this.lol;
      this.lol = lol;
      _changeSupport.firePropertyChange("lol", prev, lol);
   }

   public void setZombified(boolean zombified)
   {
      final boolean prev = this.zombified;
      this.zombified = zombified;
      _changeSupport.firePropertyChange("zombified", prev, zombified);

   }

   public void addPropertyChangeListener(final PropertyChangeListener listener)
   {
      _changeSupport.addPropertyChangeListener(listener);
   }
}

我想知道财产订单如何影响这样的绑定。此外,我注意到如果我想返回包裹在HBox中的节点,则绑定不再起作用。

我认为我做错了,但我无法弄清楚是什么。

1 个答案:

答案 0 :(得分:1)

您的JavaBeanIntegerProperty和JavaBeanBooleanProperty过早被垃圾收集。

方法Property.bind(Observable)使属性保持对observable的强引用,但 observable只保存对属性的弱引用!(它只在Observable上注册一个Listener有一个WeakReference回到Property)。同样,当您致电Bindings.bindBidirectional(Property, Property)时,两个属性都会相互之间保持弱引用!这是一个非常重要的细节,很难在文档中找到。

如果您只与JavaFX对象进行交互,这不是问题,因为JavaFX对象自然拥有对其所有属性的强引用。但是如果您使用JavaBeanIntegerProperty从遗留对象包装bean属性,那么bean不会持有对JavaBeanIntegerProperty的强引用,因此在gc之后,Property将消失并停止更新bean!我认为这是JavaBeanIntegerProperty中的设计错误。

解决方案是将JavaBeanIntegerProperty分配给一个字段并存储它,只要您希望绑定继续更新bean。

或者,您可以编写自己的Property子类来执行某些操作,以确保从Bean到Property存在强引用(例如,addPropertyChangeListener将直接监听bean)。