我有一个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();
}
答案 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,我喜欢使用这些层:
答案 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