2013-11-03 23 views
13

下面是一段简单的JavaFX代码,以说明我的问题。JavaFX - 数据模型类中的可观察集合

List list1 = new ArrayList(); 
list1.add("foo"); 
... 

someListView = new ListView<>(); 
ObservableList someObservableList = FXCollections.observableList(list1); 
someListView.setItems(someObservableList); 
... 

someObservableList.add("bar"); 

如果我理解正确,调用setItems方法后,不仅将在ListView GUI组件显示在列表中的内容,而且还当项目被添加到事后ObservableList情况下,ListView会自动刷新并自动显示新增项目,无需调用任何额外的addrefresh方法。

到目前为止,一切都很好。但是如果我在原始列表中添加一些东西(即list1)。这些更改不会自动传播。它非常有意义,但有时不方便。

当然,在典型的Java应用程序中,应用程序的模型不包含ObservableCollection实例。因此,无论何时向模型添加内容,您都必须更新从原始列表派生的ObservableLists实例。显然这是不可避免的,对吧?

这让我想知道,这是一个聪明的想法修改Collection类型事件(例如ListCollectionSetIterable,...)在模型类,从现在起通过其ObservableCollection的替代品取代他们?

到目前为止,我始终认为这些ObservableCollection类只能用于应用程序的Gui层,但在各处使用它们似乎相当方便。

回答

7

你可以通过花岗岩数据服务生成器(用groovy GSP和Java编写)来从你的域类生成“可绑定”java类,方法是生成javafx属性来保存包括集合在内的基本字段的数据。

有一个很好的示例项目:https://github.com/graniteds/shop-admin-javafx它是用启用代的maven构建的。这指的是DRY原则(不要重复自己),有时域类变成可绑定的东西似乎更有用。您已将类修改为拥有javafx属性:您已经完成了与Granite类似的工作,是的,由于它删除了样板代码(类似于:EJB3似乎删除DTO,实体是域类),因此具有一些优点。但是,您的域类与您的观点紧密结合:它看起来像一个MVC模式。

另一个解决方案是使用JFXtras库,它有一个有趣的API来在Java集合上实时生成监听器来实例化javafx属性。这里是一个链接,它被描述为:http://ugate.wordpress.com/2012/07/30/javafx-programmatic-pojo-expression-bindings-part-iii/

有了JFXtras,你可以使用这些属性,只有当你想要他们,与一个相对简单的API(对于集合,它可能变得很难阅读恕我直言),这样你请勿修改不会与View相关的域类。但对于收藏品的高级绑定:它似乎不是最好的解决方案。它看起来像MVC和MVP之间的妥协。

最后的解决方案,我看到的是通过引入演示层链接两个与MVP模式坚持,你实际上是使用它,这原本不允许模型类通过视图访问:http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter

您必须在您的javafx属性和您的域类之间手动实例化和同步值:有时候它是您想要的,并且是实现此目的的唯一方法(例如:通过这种方式,您可以以相当形式“恢复”旧域值很容易,如果它是可绑定的,你将失去最后的'正确的'域值)。请注意,您可以通过不同的视图访问并绑定您的javafx属性(使用IOC框架(如Spring)):我将它们视为Presenter的一部分。

我不认为有更好的解决方案:根据您的需要和您的喜好选择。它甚至可以成为经典的MVC vs MVP辩论,没有赢家。

+0

此外,在您的模型中使用JavaFX Observables会立即添加jfxrt.jar的依赖项,这会在与其他非JavaFX项目共享模型时导致问题。 – OttPrime

6

一般来说,我会在我的模型层中避免任何GUI-Library依赖项。这将限制可能的重复使用。对于javafx依赖关系以及AWT对象(例如在模型类中经常使用(错误地)使用的Point/Rectangle),这是正确的。

原因很简单:你的代码会限制自己的平台和框架,Android例如不支持任何提到的Java UI层,如awt。另外,ORM可能会遇到这种类型的问题,这些类型需要您的域对象使用自定义适配器。

我发现使用MVVM模式的稍微修改版本也适用于javafx。在你的例子中,你可以用普通的List和适当的propertychange事件来设计你的模型。 ViewModel将作为模型的适配器工作,提供视图可绑定到的ObservableList。

  • 使用* .fxml观点: 你必须用JavaFX控制器,它会简单地创建绑定到视图模型
  • 使用代码生成的观点: 就在您的视图中添加一个构造函数依赖关系所需的ViewModel并在视图中绑定到属性。

ViewModels通常包含一些样板代码,您可能需要避免这些代码。然而,虚拟机也让你有机会做一些魔术,也就是使用反射自动生成这些List + Events到ObservableCollection。

有关MVC的最后一句话:Swing和javafx不是用于MVC方式(因为控制器被合并到视图中)。 MVC适用于组件,其中MVP和MVVM更适合于应用程序。