我正在尝试确定是否有一种方法可以从fxml加载ListProperty
,例如SimpleListProperty<InteractionDefinition>
,而不包括FXCollections
层。有没有办法使案例1像案例2一样起作用?
public class AppMenuItem extends MenuItem {
private SimpleListProperty<InteractionDefinition> interactions = new SimpleListProperty<>();
public void setInteractions(ObservableList<InteractionDefintion> interactionsTmp);
}
案例1
<AppMenuItem id="AppMenuItem2" menuText="View 2" fx:id="asdDefaultView2MenuItem">
<interactions>
<InteractionDefinition action="actionName" button="ACTION" device="MOUSE" event="CLICK" />
<InteractionDefinition action="actionName" button="ACTION" device="MOUSE" event="CLICK" />
<InteractionDefinition action="actionName" button="ACTION" device="MOUSE" event="CLICK" />
</interactions>
</AppMenuItem >
案例2
<AppMenuItem id="AppMenuItem2" menuText="View 2" fx:id="asdDefaultView2MenuItem">
<interactions>
<FXCollections fx:factory="observableArrayList">
<InteractionDefinition action="actionName" button="ACTION" device="MOUSE" event="CLICK" />
<InteractionDefinition action="actionName" button="ACTION" device="MOUSE" event="CLICK" />
<InteractionDefinition action="actionName" button="ACTION" device="MOUSE" event="CLICK" />
</FXCollections>
</interactions>
</AppMenuItem >
答案 0 :(得分:2)
问题在于设置方法的存在。在 FXML简介文档的Property Elements部分,您将看到:
属性元素
其标签名称以小写字母开头的元素表示对象属性。属性元素可以表示以下其中一项:
- 属性设置器
- 只读列表属性
- 只读地图属性
属性设置器
如果元素代表属性设置器,则该元素的内容(必须是文本节点或嵌套类实例元素)作为值传递给属性的设置器。
...
只读列表属性
只读列表属性是Bean属性,其getter返回
java.util.List
的实例,并且没有相应的setter方法。只读列表元素的内容在处理时会自动添加到列表中。...
当FXMLLoader
处理<interactions>
标签时,它将尝试使用标签内定义的对象来更新相应的属性。如何更新属性取决于上述文档中指定的规则-上面引用了其中的一些规则。由于您有一个setter方法(形式为setInteractions(ObservableList)
),它将尝试将标签中定义的对象强制转换为ObservableList
并使用setter方法;这是因为属性元素被确定为“属性设置器”,而不是“只读列表属性”。因此,情况1 失败,因为您没有定义ObservableList
,而是定义了多个InteractionDefinition
。
如果要使用案例1 ,则需要将iteractions
属性设置为只读,并添加一个getter方法。从FXMLLoader
的角度来看,该属性仅需为只读。换句话说,只要您没有遵循标准Java Bean约定的setter方法,FXMLLoader
就会假定该属性为只读。
至少,将代码更改为以下内容将允许您使用案例1 :
public class AppMenuItem extends MenuItem {
private SimpleListProperty<InteractionDefinition> interactions = new SimpleListProperty<>();
public ObservableList<InteractionDefinition> getInteractions() {
return iteractions.get();
}
}
如果您决定使该属性为完全只读,则可以使用ReadOnlyListWrapper
。或者,如果您不需要完整的JavaFX属性,则可以直接使用ObservableList
。
但是,有些事情似乎与刚才所说的一切相矛盾。例如,如果您定义ListView
,则在FXML中,您还可以为其items
属性定义元素。此属性不是“只读列表属性”,因为它定义了一个setter(因为items
是ObjectProperty<ObservableList<T>>
)。尽管如此,以下内容仍然有效:
<ListView>
<String fx:value="Item #1"/>
</ListView>
由于有一个setter并且使用了ObservableList
而不是String
,所以您会期望得到强制错误。有趣的是,如果稍微更改FXML,您将 得到错误。
<ListView>
<items>
<String fx:value="Item #1"/>
</items>
</ListView>
现在抛出一个错误。那有什么呢?我能发现的唯一区别是使用@DefaultProperty
。如果指定了默认属性,并且您不要在FXML文件中显式使用元素标记(例如<items>
),则会显示该属性,它的作用类似于“只读列表属性”( (如果默认属性是或包含List
),而不是“属性设置器”。一旦您执行明确使用了元素标记(例如<items>
),它的行为将与该答案的第一部分中所述的一样。 我找不到明确描述此行为的文档,这可能意味着它是一个错误。此外,请注意,我仅在Java 10.0.2上尝试过此操作。
如果您要依靠它,并且由于MenuItem
没有DefaultProperty
,则可以尝试使用以下内容:
Java代码:
@DefaultProperty("interactions")
public class AppMenuItem extends MenuItem {
private final ListProperty<InteractionDefintion> interactions = new SimpleListProperty<>(this, "interactions");
public final void setInteractions(ObservableList<InteractionDefinition> interactions) {
this.interactions.set(interactions);
}
public final ObservableList<InteractionDefinition> getInteractions() {
return interactions.get();
}
public final ListProperty<InteractionDefinition> interactionsProperty() {
return interactions;
}
}
FXML文件:
<AppMenuItem id="AppMenuItem2" menuText="View 2" fx:id="asdDefaultView2MenuItem">
<InteractionDefinition action="actionName" button="ACTION" device="MOUSE" event="CLICK" />
<InteractionDefinition action="actionName" button="ACTION" device="MOUSE" event="CLICK" />
<InteractionDefinition action="actionName" button="ACTION" device="MOUSE" event="CLICK" />
</AppMenuItem >