2016-04-26 6 views
1

null -safe BooleanBindingを作成する手助けが必要です。 null -safeである必要があります。なぜなら、モデルのすべての属性にデフォルト値を指定することができないからです(1つの理由:モデルに列挙型が含まれています)。JavaFXでヌルセーフなBooleanBindingを作成する8

executeButtonDisabled.bind(missionProperty().isNotNull().and(missionProperty().get().statusProperty().isNotEqualTo(MissionStatus.CREATED))); 
    final BooleanBinding isNotExecutingBinding = missionProperty().isNotNull().and(missionProperty().get().statusProperty().isNotEqualTo(MissionStatus.EXECUTING)); 
    completeButtonDisabled.bind(isNotExecutingBinding); 
    cancelButtonDisabled.bind(isNotExecutingBinding) 

しかし、完全な表現がNullPointerExceptionにもたらされる評価されます(ただし、プロパティが用意されている場合、それは正しく、ボタンを更新します)ので、そのアプローチは動作しません:次のように私の最初のアプローチがされています。今はBindingsクラスをJavaFX binding and null valuesのように使用しようとしていますが、動作させることはできません。現在のアプローチは次のとおりです。

final BooleanBinding isNotCreatedBinding = Bindings.createBooleanBinding(
      () -> mission.isNull().getValue() 
        ? true 
        : missionProperty().get().statusProperty().isNotEqualTo(MissionStatus.CREATED).getValue()); 
    final BooleanBinding isNotExecutingBinding = Bindings.createBooleanBinding(
      () -> mission.isNull().getValue() 
        ? true 
        : missionProperty().get().statusProperty().isNotEqualTo(MissionStatus.EXECUTING).getValue()); 

    executeButtonDisabled.bind(isNotCreatedBinding); 
    completeButtonDisabled.bind(isNotExecutingBinding); 
    cancelButtonDisabled.bind(isNotExecutingBinding); 

しかし、これはうまくいかず、なぜ私は理解できません。 modelProperty()のプロパティバインディングはここでは機能しません。最初の作業用ソリューション(少なくともnullなし)を適切なnullセーフソリューションに変換する方法を私に説明できますか?

編集2016年4月26日:

Mission.java

package de.florianwolters.example.javafx.bindings; 

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

public class Mission { 

    enum Status { 
     CREATED, 
     EXECUTING, 
     COMPLETED, 
     CANCELED; 
    } 

    private final StringProperty shortName = new SimpleStringProperty(); 

    private final ObjectProperty<Status> status = new SimpleObjectProperty<>(); 

    public Mission(final String shortName) { 
     this.setShortName(shortName); 
     this.setStatus(Status.CREATED); 
    } 

    public String getShortName() { 
     return shortNameProperty().get(); 
    } 

    public void setShortName(final String shortName) { 
     shortNameProperty().set(shortName); 
    } 

    public StringProperty shortNameProperty() { 
     return shortName; 
    } 

    public Status getStatus() { 
     return statusProperty().get(); 
    } 

    public void setStatus(final Status status) { 
     statusProperty().set(status); 
    } 

    public ObjectProperty<Status> statusProperty() { 
     return status; 
    } 
} 

MissionDetailsViewModel.java

package de.florianwolters.example.javafx.bindings; 

import javafx.beans.binding.Bindings; 
import javafx.beans.binding.BooleanBinding; 
import javafx.beans.property.ObjectProperty; 
import javafx.beans.property.ReadOnlyBooleanProperty; 
import javafx.beans.property.ReadOnlyBooleanWrapper; 
import javafx.beans.property.SimpleObjectProperty; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

public final class MissionDetailsViewModel { 

    /** 
    * The logger used for logging in the `MissionDetailsViewModel` class. 
    */ 
    private static final Logger LOGGER = LoggerFactory.getLogger(
     MissionDetailsViewModel.class); 

    private ObjectProperty<Mission> mission = new SimpleObjectProperty<>(); 

    private final ReadOnlyBooleanWrapper executeButtonDisabled = new ReadOnlyBooleanWrapper(true); 

    private final ReadOnlyBooleanWrapper completeButtonDisabled = new ReadOnlyBooleanWrapper(true); 

    private final ReadOnlyBooleanWrapper cancelButtonDisabled = new ReadOnlyBooleanWrapper(true); 

    /** 
    * Constructs a `MissionDetailsViewModel`. 
    */ 
    public MissionDetailsViewModel(final ObjectProperty<Mission> mission) { 
     this.mission.bind(mission); 
//  partialWorkingBinding(); 
     notWorkingBinding(); 
    } 

    private void notWorkingBinding() { 
     final BooleanBinding isNotCreatedBinding = Bindings.createBooleanBinding(
      () -> missionProperty().isNull().get() 
       ? true 
       : missionProperty().get().statusProperty().isNotEqualTo(Mission.Status.CREATED).get(), 
      missionProperty()); 

     final BooleanBinding isNotExecutingBinding = Bindings.createBooleanBinding(
      () -> mission.isNull().get() 
       ? true 
       : missionProperty().get().statusProperty().isNotEqualTo(Mission.Status.EXECUTING).get(), 
      missionProperty()); 

     executeButtonDisabled.bind(isNotCreatedBinding); 
     completeButtonDisabled.bind(isNotExecutingBinding); 
     cancelButtonDisabled.bind(isNotExecutingBinding); 
    } 

    private void partialWorkingBinding() { 
     executeButtonDisabled.bind(missionProperty().isNotNull().and(missionProperty().get().statusProperty().isNotEqualTo(Mission.Status.CREATED))); 
     final BooleanBinding isNotExecutingBinding = missionProperty().isNotNull().and(missionProperty().get().statusProperty().isNotEqualTo(Mission.Status.EXECUTING)); 
     completeButtonDisabled.bind(isNotExecutingBinding); 
     cancelButtonDisabled.bind(isNotExecutingBinding); 
    } 

    public boolean isExecuteButtonDisabled() { 
     return executeButtonDisabledProperty().get(); 
    } 

    public ReadOnlyBooleanProperty executeButtonDisabledProperty() { 
     return executeButtonDisabled; 
    } 

    public boolean isCompleteButtonDisabled() { 
     return completeButtonDisabledProperty().get(); 
    } 

    public ReadOnlyBooleanProperty completeButtonDisabledProperty() { 
     return completeButtonDisabled; 
    } 

    public boolean isCancelButtonDisabled() { 
     return cancelButtonDisabledProperty().get(); 
    } 

    public ReadOnlyBooleanProperty cancelButtonDisabledProperty() { 
     return cancelButtonDisabled; 
    } 

    public Mission getMission() { 
     return missionProperty().get(); 
    } 

    public void setMission(final Mission mission) { 
     missionProperty().set(mission); 
    } 

    public ObjectProperty<Mission> missionProperty() { 
     return mission; 
    } 
} 
提案ソリューションが動作しませんが、それゆえ私は、単純な完全に動作する例を作成しました

MissionDetailsViewModelTest.java

package de.florianwolters.example.javafx.bindings; 

import static eu.lestard.assertj.javafx.api.Assertions.assertThat; 
import javafx.beans.property.SimpleObjectProperty; 

import org.junit.Before; 
import org.junit.Test; 

public final class MissionDetailsViewModelTest { 
    private Mission mission; 
    private MissionDetailsViewModel viewModel; 

    @Before 
    public void setUp() { 
     mission = new Mission("My Short Name"); 
    viewModel = new MissionDetailsViewModel(new SimpleObjectProperty<Mission>(mission)); 
    } 

    @Test 
    public void testInitialValues() { 
     assertThat(viewModel.executeButtonDisabledProperty()).isFalse(); 
     assertThat(viewModel.completeButtonDisabledProperty()).isTrue(); 
     assertThat(viewModel.cancelButtonDisabledProperty()).isTrue(); 
    } 

    @Test 
    public void testMissionStatusSetToExecuting() { 
     mission.setStatus(Mission.Status.EXECUTING); 
     assertThat(viewModel.executeButtonDisabledProperty()).isTrue(); 
     assertThat(viewModel.completeButtonDisabledProperty()).isFalse(); 
     assertThat(viewModel.cancelButtonDisabledProperty()).isFalse(); 
    } 

    @Test 
    public void testMissionStatusSetToCompleted() { 
     mission.setStatus(Mission.Status.COMPLETED); 
     assertThat(viewModel.executeButtonDisabledProperty()).isTrue(); 
     assertThat(viewModel.completeButtonDisabledProperty()).isTrue(); 
     assertThat(viewModel.cancelButtonDisabledProperty()).isTrue(); 
    } 

    @Test 
    public void testMissionStatusSetToCanceled() { 
     mission.setStatus(Mission.Status.CANCELED); 
     assertThat(viewModel.executeButtonDisabledProperty()).isTrue(); 
     assertThat(viewModel.completeButtonDisabledProperty()).isTrue(); 
     assertThat(viewModel.cancelButtonDisabledProperty()).isTrue(); 
    } 
} 

ユニットテストは、上記のコード(notWorkingBinding()が使用されている方法)で失敗したが、方法partialWorkingBinding()と連携します。私は間違って何をしていますか?

答えて

3

isNotCreatedBindingの計算機能を設定しましたが、バインディングの依存関係は設定していません。あなたは依存関係としてmisionを追加する必要があります。あなたはmissionPropertyは、()(取得するときcreateBooleanBindingでは動作しませんこれは、statusProperty代わりのmissionPropertyに耳を傾ける必要がある

Bindings.createBooleanBinding(
     () -> mission.isNull().getValue() 
       ? true 
       : missionProperty().get().statusProperty().isNotEqualTo(MissionStatus.CREATED).getValue(), mission); 

EDIT

)== nullを。

しかし、あなたはバインディング Whenを使用することができます。

(既に問題に言及したNullPointerExceptionを引き起こしている)

BooleanBinding isNotCreatedBinding = new When(mission.isNotNull()).then(mission.get().statusProperty().isNotEqualTo(Mission.Status.CREATED)).otherwise(false); 

以上の低レベルのソリューション:

missionProperty().addListener((ov, m, m1) -> { 
      if (m1 != null) { 
       executeButtonDisabled.bind(m1.statusProperty().isNotEqualTo(Mission.Status.CREATED)); 
      }else { 
       executeButtonDisabled.unbind(); 
       executeButtonDisabled.set(false); 
      } 
     }); 
+0

ありがとうございますが、動作しません。最新の質問を参照してください。私は単体テストを含む完全な例を提供しました。 –

+0

私のアンサーを更新しました – jns

+0

ありがとうございますが、私は 'When'バインディングで' NullPointerException'を得ています。これは私を夢中にさせている、私はこれが非常に一般的な使用例だと思う。最初は「null」に設定されているマスタービュー(たとえば、ListView)の選択について考えてみてください。詳細ビューの「ミッション」をマスタービューの選択にバインドしますが、動作させることはできません。 –

2

Tomas MikulaのReactFX framework (v 2.0)には、この機能が組み込まれています。

import org.reactfx.value.Val; 

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

public class NestedBindingTest { 
    public static void main(String[] args) { 
     BooleanProperty disable = new SimpleBooleanProperty(); 
     disable.addListener((obs, wasDisabled, isNowDisabled) -> 
      System.out.println("disable: "+wasDisabled+" -> "+isNowDisabled)); 

     ObjectProperty<Item> item = new SimpleObjectProperty<>(); 

     Val<Item.Status> status = Val.flatMap(item, Item::statusProperty); 
     disable.bind(status.map(s -> s == Item.Status.PENDING).orElseConst(true)); 

     Item i = new Item(); 
     System.out.println("Setting item"); 
     item.set(i); 

     System.out.println("Setting item status to PENDING"); 
     i.setStatus(Item.Status.PENDING); 

     System.out.println("Setting item status to READY"); 
     i.setStatus(Item.Status.READY); 

     System.out.println("Setting item to null"); 
     item.set(null); 
    } 

    public static class Item { 
     public enum Status {PENDING, READY} 

     private final ObjectProperty<Status> status = new SimpleObjectProperty<>(); 

     public final ObjectProperty<Status> statusProperty() { 
      return this.status; 
     } 


     public final NestedBindingTest.Item.Status getStatus() { 
      return this.statusProperty().get(); 
     } 


     public final void setStatus(final NestedBindingTest.Item.Status status) { 
      this.statusProperty().set(status); 
     } 



    } 
} 
関連する問題