使用JavaFX 8创建一个空安全BooleanBinding [英] Create a null-safe BooleanBinding with JavaFX 8

查看:255
本文介绍了使用JavaFX 8创建一个空安全BooleanBinding的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要帮助创建一个 -safe BooleanBinding 。它必须是 -safe因为我不能对模型中的所有属性提供缺省值(一个原因:模型包含枚举)。我的第一个方法是如下:

I need help creating a null-safe BooleanBinding. It has to be null-safe since I can not provide default values for all attributes in the model (one reason: the model contains enumerations). My first approach has been as follows:

    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)

但由于完整的前pression评估这导致方法不起作用一个 NullPointerException异常(但它正确更新按钮,提供物业时)。现在我试图使用绑定类中的 JavaFX绑定和空值,但我不能使它工作。这是我目前的做法:

But that approach does not work because the complete expression is evaluated which results in a NullPointerException (but it correctly updates the buttons, when a property is provided). Now I am trying to use the Bindings class as suggested in JavaFX binding and null values, but I can't make it work. Here's my current approach:

    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()结合不在这里工作了!你能向我解释如何对第一个工作的解决方案转换(至少在没有)以适当的 - 安全的解决方案?

But this does not work and I do not understand why. It seems that the property binding for modelProperty() does not work here! Can you explain to me how-to convert the first working solution (at least without null) to a proper null-safe solution?

修改2016年4月26日:建议的解决方案不起作用,所以我创建了一个简单的完全正常的工作例如:

Edit 2016-04-26: The suggested solution does not work, therefore I created a simple fully-working example:

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();
    }
}

单元测试失败与code以上(方法 notWorkingBinding()使用),但该方法适用 partialWorkingBinding() 。我在做什么错了?

The unit test fails with the code above (the method notWorkingBinding() is used) but works with the method partialWorkingBinding(). What am I doing wrong?

推荐答案

您设置了 isNotCreatedBinding 计算功能,但你没有设置的依赖关系为绑定。您需要添加米西的依赖性:

You set up the calculation function for isNotCreatedBinding, but you didn't set the dependencies for the binding. You need to add mision as dependency:

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

修改

您需要听statusProperty而不是missionProperty,不会与 createBooleanBinding 时missionProperty()。获得()== NULL工作。

You need to listen to the statusProperty instead of missionProperty, which will not work with createBooleanBinding when missionProperty().get() == null.

<击>但是,你可以使用绑定:

(是造成 NullPointerException异常中的问题已经提到)

(is causing a NullPointerException as already mentioned in the question)

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

还是比较低层次的解决方案:

Or a more low-level solution:

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

这篇关于使用JavaFX 8创建一个空安全BooleanBinding的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆