为了账号安全,请及时绑定邮箱和手机立即绑定

JavaFX - 无法将对象强制为 SimpleListProperty

JavaFX - 无法将对象强制为 SimpleListProperty

撒科打诨 2021-09-12 19:44:58
我正在尝试确定是否有办法从 fxml加载ListProperty, like 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 >案例二<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 >
查看完整描述

1 回答

?
守着星空守着你

TA贡献1799条经验 获得超8个赞

回答

问题是存在 setter 方法。在FXML 简介文档的属性元素部分,您将看到:

属性元素

标签名称以小写字母开头的元素表示对象属性。一个属性元素可以代表以下之一:

  • 属性设置器

  • 只读列表属性

  • 只读地图属性

属性设置器

如果元素表示属性设置器,则元素的内容(必须是文本节点或嵌套的类实例元素)将作为值传递给属性的设置器。

...

只读列表属性

只读列表属性是一个 Bean 属性,它的 getter 返回一个实例java.util.List并且没有相应的 setter 方法。只读列表元素的内容在处理时会自动添加到列表中。

...

FXMLLoader处理<interactions>标记时,它将尝试使用标记内定义的对象更新相应的属性。它如何更新属性受上述文件中指定的规则的约束——其中一些已在上面引用。由于您有一个 setter 方法(以 的形式setInteractions(ObservableList)),它会尝试将标签中定义的对象强制转换为 anObservableList并使用 setter 方法;这是因为属性元素被确定为“属性设置器”而不是“只读列表属性”。因此,案例 1失败了,因为您没有定义一个ObservableList而是多个InteractionDefinitions。

如果您想使用案例 1,您需要将该iteractions属性设为只读并添加一个 getter 方法。从FXMLLoader. 换句话说,只要您没有遵循标准 Java Bean 约定的 setter 方法,FXMLLoader就会假定该属性是只读的。

至少,将您的代码更改为以下内容将允许您使用Case 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. 如果指定了默认属性并且您没有<items>在 FXML 文件中明确使用元素标记(例如),那么它将表现为“只读列表属性”(如果默认属性是或包含 a 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 >


查看完整回答
反对 回复 2021-09-12
  • 1 回答
  • 0 关注
  • 308 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信