2017-07-13 8 views
0

要素の1つがそのプロパティ(更新イベント)の1つを変更した場合、抽出器(Callback<E, Observable[]> extractor)を使用して火災変更イベントをListPropertyに変更できます。ObjectPropertyからイベントを更新する(ObservableListと同様)

Update Change Event in ObservableList

ObjectProperty<>の等価はありますか?私はSimpleObjectPropertyを持っています。イベントのプロパティ(別のBeanタイプ)の変更(変更イベントの更新)が発生したときにイベントを発生させたいのです。

サンプルコード:

public class TestBean { 

    public static <T extends TestBean> Callback<T, Observable[]> extractor() { 

    return (final T o) -> new Observable[] { o.testPropertyProperty() }; 
    } 

    private final StringProperty testProperty = new SimpleStringProperty(); 

    public final StringProperty testPropertyProperty() { 
    return this.testProperty; 
    } 

    public final String getTestProperty() { 
    return this.testPropertyProperty().get(); 
    } 

    public final void setTestProperty(final String testProperty) { 
    this.testPropertyProperty().set(testProperty); 
    } 

} 

public class SomeType { 

    /** 
    * How can I listen for changes of TestBean#testProperty? 
    */ 
    private final ObjectProperty<TestBean> property = new SimpleObjectProperty<>(); 

} 

SomeType#property#testProperty変更された場合、私は、SomeType#propertyの値が変化した場合に変更イベントを受信したいが、また。

SomeType#propertyが変更されたときに通知されないため、私はちょうどSomeType#property#testPropertyを聞くことができません(変更のために間違ったオブジェクトを聞きます)。

+0

ですから、 'SimpleObjectProperty'の値の変更を聞きたいですか? – Sunflame

+0

私は質問を更新しました、私はそれが今より明確であることを願っています。 – kerner1000

答えて

-1

だから、私はあなたのオブジェクトにリスナーが必要だと思います、それは簡単に行うことができます。まず第一に、あなたはこの方法コンストラクタとし、ゲッターとあなたのクラスを記述する必要があります:あなたは、単にその後、propertyプロパティのtestProperty()を取得して

import javafx.beans.property.ObjectProperty; 
import javafx.beans.property.SimpleObjectProperty; 

public class SomeType { 

    public ObjectProperty<TestProperty> property; 

    public SomeType(TestProperty testProperty) { 
     this.property = new SimpleObjectProperty<>(testProperty); 
    } 

    public TestProperty getProperty() { 
     return property.get(); 
    } 

    public ObjectProperty<TestProperty> propertyProperty() { 
     return property; 
    } 
} 

は次にどこでも、あなたは、あなたがプロパティをチェーンできSomeTypeのインスタンスを持っていますリスナーを追加します。

someType.getProperty().testProperty().addListener((observable, oldValue, newValue) -> { 
     // do whatever you want if the its value change 
     // you can also use its old or new value. 
    }); 
+0

'SomeType#set(new TestProperty());を呼び出すと、これは動作しません;私は変更のために古いBeanをリッスンします。 – kerner1000

0

私は、次のを思い付いた:

public class ObservableValueProperty<T> extends SimpleObjectProperty<T> { 

    private InvalidationListener listener = null; 

    private final Callback<T, Observable[]> extractor; 

    public ObservableValueProperty() { 
    this(null); 
    } 

    public ObservableValueProperty(final Callback<T, Observable[]> extractor) { 
    this.extractor = extractor; 
    } 

    @Override 
    protected void fireValueChangedEvent() { 
    super.fireValueChangedEvent(); 
    } 

    @Override 
    public void setValue(final T v) { 
    if (extractor != null) { 
     final T oldValue = super.get(); 
     if (oldValue != null) { 
     for (final Observable o : extractor.call(oldValue)) { 
      o.removeListener(listener); 
     } 
     } 
     listener = o -> fireValueChangedEvent(); 
     for (final Observable o : extractor.call(v)) { 
     o.addListener(listener); 
     } 
    } 
    super.setValue(v); 
    } 
} 

public class ObservableValuePropertyTest4 implements ChangeListener<Object> { 

    @BeforeClass 
    public static void setUpBeforeClass() throws Exception { 
    } 

    @AfterClass 
    public static void tearDownAfterClass() throws Exception { 
    } 

    @Before 
    public void setUp() throws Exception { 
    } 

    @After 
    public void tearDown() throws Exception { 
    } 

    static class NestedBean { 

    StringProperty nestedProperty = new SimpleStringProperty("hans"); 

    public static <T extends NestedBean> Callback<T, Observable[]> extractor() { 

     return (final T o) -> new Observable[] { o.nestedProperty }; 
    } 

    @Override 
    public boolean equals(final Object obj) { 
     if (obj instanceof NestedBean) { 
     System.err.println(this.nestedProperty.get() + " " + ((NestedBean) obj).nestedProperty.get()); 
     return Objects.equal(this.nestedProperty.get(), ((NestedBean) obj).nestedProperty.get()); 
     } 
     return false; 
    } 

    } 

    private ObservableValueProperty<NestedBean> p; 

    private NestedBean nestedBean; 

    private String newNestedValue = null; 

    @Test 
    public void test01() { 
    p = new ObservableValueProperty<>(NestedBean.extractor()); 
    nestedBean = new NestedBean(); 
    p.setValue(nestedBean); 
    p.addListener(this); 
    nestedBean.nestedProperty.set("peter"); 
    assertEquals("peter", newNestedValue); 
    } 

    @Override 
    public void changed(final ObservableValue<? extends Object> observable, final Object oldValue, 
     final Object newValue) { 
    System.err.println("Changed"); 
    newNestedValue = nestedBean.nestedProperty.get(); 

    } 

} 

残念ながら、これが原因でExpressionHelper$SingleChangeのいずれかの変更イベントを発生しません:

@Override 
     protected void fireValueChangedEvent() { 
      final T oldValue = currentValue; 
      currentValue = observable.getValue(); 
      final boolean changed = (currentValue == null)? (oldValue != null) : !currentValue.equals(oldValue); 
      if (changed) { 
       try { 
        listener.changed(observable, oldValue, currentValue); 
       } catch (Exception e) { 
        Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e); 
       } 
      } 
     } 

これは平等のためにチェックした場合のみ等しくありませんすべてのリスナーに通知します。 fireValueChangedEvent()をトリガーすると、値はすでに変更されており、新しい値と古い値が等しいため、リスナーには通知されません。

1

SomeType#property#testProperty変更された場合、私は、SomeType#propertyの値が変化した場合に変更イベントを受信したいが、また。

SomeType#propertyが変更されたとき、私は(私は、その後の変更のために間違ったオブジェクトに聞くでしょう)、通知されませんので、私はちょうど、SomeType#property#testPropertyをリッスンすることはできません。

これはJavaFXの現在の反復の種類の制限です。組み込みの方法は信頼性が低く、サードパーティのライブラリを使用する方が良いです。詳細については、answerを参照してください。あなたのケースでは

、ReactFXは同様の方法で利用することができます。

import javafx.beans.property.ObjectProperty; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 

import org.reactfx.value.Val; 
import org.reactfx.value.Var; 

class TestBean { 

    private final StringProperty testProperty = new SimpleStringProperty(); 
    public final StringProperty testPropertyProperty()  { return testProperty; } 
    public final String getTestProperty()      { return testProperty.get(); } 
    public final void setTestProperty(String newTestProperty) { testProperty.set(newTestProperty); } 
} 

public class SomeType { 

    private final ObjectProperty<TestBean> property = new SimpleObjectProperty<>(); 
    public final ObjectProperty<TestBean> propertyProperty() { return property; } 
    public final TestBean getProperty()      { return property.get(); } 
    public final void setProperty(TestBean newProperty)  { property.set(newProperty); } 

    public static void main(String[] args) { 
     SomeType someType = new SomeType(); 
     Var<String> chainedTestProperty = Val.selectVar(someType.propertyProperty(), TestBean::testPropertyProperty); 
     chainedTestProperty.addListener((obs, oldVal, newVal) -> System.out.println(obs + " " + oldVal + "->" + newVal)); 

     //Tests 
     someType.setProperty(new TestBean()); 
     someType.getProperty().setTestProperty("s1"); 
     TestBean bean2 = new TestBean(); 
     bean2.setTestProperty("s2"); 
     someType.setProperty(bean2); 
     someType.setProperty(new TestBean()); 
    } 
} 

出力:

[email protected] null->s1 
[email protected] s1->s2 
[email protected] s2->null 

キーライン

Var<String> chainedTestProperty = Val.selectVar(someType.propertyProperty(), TestBean::testPropertyProperty); 

はリスナーチェーンの一種です。第1引数は、タイプTypeのプロパティ(OvservableValue)です。 2番目の引数は、Typeからそのプロパティに与えられたの中のTypeの中のいくつかの他の型の "サブ"プロパティです。

現在、チェーン内の「リンク」が変更されるたびに通知されます。このようにしてovservablesを連続的に連鎖させることによって、サブサブプロパティの変更を引き続き聞くことができます。

1

私は先週と同じ問題を抱えていたし、多くの試行の後、私は期待どおりに動作しているようだ解決策を見つけた:

  • 私はObjectProperty<E>の同じインタフェースを持っているObjectXProperty<E>と呼ばれる新しいクラスを作成;
  • それはCallback<E,Observable[]>を受け入れることができるコンストラクタを持っています。
  • ObjectXPropertyの中には、すべてのメソッドを無効にするSimpleObjectPropertyを使用しています。
  • マジックのトリックはset(E value)方法である:私は単にを送り返すObjectBindingを作成し、それが無効になっていたときにそれが決定する抽出機能を使用しています!

  • bindメソッドが以前にObjectXPropertyで使用されていた場合、このトリックは適用されません。 unbindメソッドが呼び出された場合は再び動作します。

ここに私の新しいクラスObjectXProperty<E>です:

import javafx.beans.InvalidationListener; 
import javafx.beans.Observable; 
import javafx.beans.binding.Bindings; 
import javafx.beans.property.ObjectProperty; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.util.Callback; 

/** 
* 
* @author Claude Bouchard - 2017 
*/ 

public class ObjectXProperty<E> extends ObjectProperty<E> { 

SimpleObjectProperty<E> p; 
Callback<E, Observable[]> extractor; 

boolean externalBound = false; 

public ObjectXProperty(Callback<E, Observable[]> extractor) { 
    this.extractor = extractor; 
} 

public ObjectXProperty(E init, Callback<E, Observable[]> extractor) { 

    p = new SimpleObjectProperty(); 
    this.extractor = extractor; 
    set(init); 

} 

public ObjectXProperty(Object bean, String name, Callback<E, Observable[]> extractor) { 
    p = new SimpleObjectProperty(bean, name); 
    this.extractor = extractor; 
} 

public ObjectXProperty(Object bean, String name, E init, Callback<E, Observable[]> extractor) { 
    p = new SimpleObjectProperty(bean, name); 
    this.extractor = extractor; 
    set(init); 

} 

@Override 
public void set(E value) { 
    if (!externalBound) { 
     if (value != null) { 
      p.bind(Bindings.createObjectBinding(() -> { 
       return value; 
      }, extractor.call(value))); 

     } else { 
      p.bind(Bindings.createObjectBinding(() -> { 
       return value; 
      }, new Observable[]{})); 
     } 
    } else { 
     p.set(value); //As expected, it will throw a java.lang.RuntimeException 
    } 
} 

@Override 
public E get() { 
    return p.get(); 
} 

@Override 
public void addListener(ChangeListener<? super E> listener) { 
    p.addListener(listener); 
} 

@Override 
public void removeListener(ChangeListener<? super E> listener) { 
    p.removeListener(listener); 
} 

@Override 
public void addListener(InvalidationListener listener) { 
    p.addListener(listener); 
} 

@Override 
public void removeListener(InvalidationListener listener) { 
    p.removeListener(listener); 
} 

@Override 
public Object getBean() { 
    return p.getBean(); 
} 

@Override 
public String getName() { 
    return p.getName(); 
} 

@Override 
public void bind(ObservableValue<? extends E> observable) { 
    p.bind(observable); 
    externalBound = true; 
} 

@Override 
public void unbind() { 
    p.unbind(); 
    externalBound = false; 
    set(get()); //to reactivate the extractor on the last value 
} 

@Override 
public boolean isBound() { 
    return externalBound; 
} 

}

関連する問題