下面是一段简单的 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组件中,如果添加了item也会显示到 ObservableList
实例之后, ListView
将自动刷新并自动显示新添加的项目,无需调用任何额外的 add
或 refresh
方法。
到目前为止,还不错。但是,如果我向原始列表中添加一些内容(即 list1
)会怎样?这些更改不会自动传播。这很有道理,但有时会带来不便。
当然,在经典的 Java 应用程序中,应用程序的模型并不由 ObservableCollection
实例组成。因此,无论何时向模型添加内容,都必须更新从原始列表派生的 ObservableLists
实例。显然这是不可避免的,对吧?
这让我想知道,修改 Collection
类型的出现(例如 List
、Collection
、Set
, Iterable
, ...) 并从现在开始用它们的 ObservableCollection
替代品替换它们?
直到现在我一直认为这些 ObservableCollection
类只应该在应用程序的 Gui 层中使用,但在任何地方使用它们似乎都很方便。
最佳答案
您可以破解 Granite 数据服务生成器(用 groovy GSP 和 Java 编写),通过生成 javafx 属性来从您的域类生成“可绑定(bind)”java 类,以保存基本字段(包括集合)的数据。
有一个很好的示例项目:https://github.com/graniteds/shop-admin-javafx它是用 Maven 构建的,启用了生成。这指的是 DRY 原则(不要重复自己),有时领域类成为可绑定(bind)的似乎更有用。您修改了您的类以具有 javafx 属性:您做了类似于 Granite 的事情,是的,它有一些优势,因为它删除了样板代码(类似于:EJB3 似乎删除了 DTO,实体是域类)。但是您的域类与您的 View 紧密耦合:它看起来像 MVC 模式。
另一种解决方案是使用 JFXtras 库,它有一个有趣的 API,可以在 java 集合上动态生成监听器,以实例化 javafx 属性。这是描述它的链接:http://ugate.wordpress.com/2012/07/30/javafx-programmatic-pojo-expression-bindings-part-iii/
使用 JFXtras,您可以仅在需要时使用这些属性,使用相对简单的 API(对于集合,恕我直言,它可能变得难以阅读),这样您就不会修改您的域类成为 View 相关。但是对于集合的高级绑定(bind):它似乎不是最好的解决方案。它看起来像是 MVC 和 MVP 之间的折衷。
我看到的最后一个解决方案是坚持使用 MVP 模式,您实际上正在使用它,它最初不允许通过引入 Presenter 层来链接两者来通过 View 访问 Model 类:http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter
您将不得不在 javafx 属性和域类之间手动实例化和同步值:有时这是您想要的,也是实现此目的的唯一方法(例如:这样您可以“恢复”到旧域值一个很容易的表单,如果它是可绑定(bind)的,你就会丢失最后一个“正确的”域值)。请注意,您可以将 javafx 属性放在单例中(使用 IOC 框架,例如 Spring),以便通过不同的 View 进行访问和绑定(bind):我将它们视为 Presenter 的一部分。
我认为没有更好的解决方案:根据您的需要和喜好进行选择。它甚至可以成为一场没有赢家的经典 MVC 与 MVP 辩论。
关于JavaFX - 数据模型类中的可观察集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19759427/