我应该在哪里验证JavaFX属性更改?

时间:2014-04-11 13:16:15

标签: java validation binding properties javafx

我有一个mvp结构化的javafx应用程序。有一个带有textfield的视图,它有自己的textProperty类型为StringProperty。还有一个包含名为Item的Object的模型。商品有IntegerProperty

现在我想在我的演示者类中绑定这两个属性,以便在一个或另一个更改时更新它们。虽然他们有不同的类型,但有可能通过以下方式绑定它们:

Bindings.bindBidirectional( textField.textProperty(), item.percentProperty(), new NumberStringConverter() );

这非常合适,除非文本字段的值被清除,这导致NullPointerException,因为textProperty的空值导致空值并在IntegerProperty中设置空值结果为NullPointerException。你能想出任何避免这种情况的方法吗?我是否必须自己编写NumberStringConverter

此外,我想定义,Item只能保持0到100之间的百分比值。当值无效时,应通知View,以便用户可以获得反馈。 我应该在哪里验证这些商业规则?

我想出了第一个例子,但我不确定,如果这应该是要走的路,所以我很好奇,如果你有更好的想法如何解决这个问题。

class PercentProperty extends SimpleIntegerProperty
{
  private InvalidValueListener invalidValueListener = null;

  public PercentProperty ( final Integer defaultValue )
  {
    set( defaultValue );
  }

  @Override
  public void set( final int newValue )
  {
    if ( isValid( newValue ) )
    {
      super.set( newValue );
      if ( invalidValueListener != null )
        invalidValueListener.validValue();
    }
    else
    {
      if ( invalidValueListener != null )
        invalidValueListener.invalidValue();
    }
  }

  private boolean isValid( final int value )
  {
    return (value >= 0 && value <= 100);//FIXME: Better use Predicates to define Rules.
  }

  public void setListener( final InvalidValueListener listener )
  {
    invalidValueListener = listener;
  }

  public void removeListener( @SuppressWarnings( "unused" ) final InvalidValueListener listener )
  {
    invalidValueListener = null;
  }

  protected void fireInvalidationValue()
  {
    invalidValueListener.invalidValue();
  }
}


interface InvalidValueListener
{
  void validValue();
  void invalidValue();
}

2 个答案:

答案 0 :(得分:2)

JavaFX是一个简单的图形工具包,而不是一个全面的框架,这意味着你必须自己设计很多东西。数据验证就是这样的事情,您必须在之前的经验和其他人的建议中找到自己的方式。

我不会绑定这两个属性:文本字段应该初始化(只是设置,不绑定,以避免在用户输入时没有明确的共识时出现故障)和模型中的值,然后整数属性应该由监听器(文本字段的ChangeListener或表单提交的监听器更新,如果适用并且取决于您的喜好),它负责验证输入并向用户报告错误。

通过这种方式,您可以分离两个确实无关的东西:一个是用于接受用户输入的小部件(需要解析以获取数字的文本),另一个是模型中的数字,用于制作计算。

作为旁注,我不会完全使用两个属性,而是重新审视你的三层分区。 MVP和所有MVC衍生产品被证明是构建GUI 工具包的良好模式,但我从未确信它们同样适合构建 GUI应用程序。我的意思是,如果你所谓的 model 是一种在应用程序的不同部分之间共享会话数据的方式(事件接收器的种类)那么它是一个完全合法的实现,否则我认为没有用在一个类中分组的独立属性束。在后一种情况下,小部件本身就是模型:

// This is the controller
public class PesonalDetails {
  // Model starts here: it's implicitely defined by the widgets
  // You may also use @FXML
  private final TextField first = new TextField();
  private final TextField last = new TextField();
  // Model ends here
} 

注意我并不是说MVC应该被丢弃,所有内容都应该在一个文件中折叠。只是MVC,MVP,MVVM是设计模式,由您决定何时,何地以及如何实施它们 - 取决于它们向您购买的数量。使用JavaFX,我喜欢使用这些层:

  • 可视布局层(使用Java或FXML实现的布局构建器)
  • 事件处理代码
  • 如果适用,则为数据访问层(您可以在此处应用模式,如ActiveRecord)

答案 1 :(得分:1)

(答案的新版本)

我认为最好的方法是不要让用户首先输入错误的值。借助JideFX Fields

,您可以轻松实现这一目标
FormattedTextField<Integer> field = new FormattedTextField<>();
field.getPatternVerifiers().put("p", new IntegerRangePatternVerifier(0, 100));
field.setPattern("p");
field.valueProperty().bindBidirectional(item.percentProperty());

特别是FormattedTextField非常方便,因为它为您进行文本到值的转换和验证,因此不需要自己实现任何实用程序类。

<强>链接:

JideFX Fields开发人员指南:http://www.jidesoft.com/jidefx/JideFX_Fields_Developer_Guide.pdf

源代码:https://github.com/jidesoft/jidefx-oss

二进制:http://search.maven.org/#search%7Cga%7C1%7Cjidefx