java - 从 fxml 实例化的 ObservableArrayList 返回值不符合预期

标签 java javafx-2 fxml

我正在尝试将字符串变量列表传递到 fxml 中的自定义 Controller 中,因此:

<Pane xmlns:fx="http://javafx.com/fxml" >
   <VBox fx:id="vbox">
      <StepChart fx:id="employment"   title="Unemployment" enabled = "true"  prefHeight="250.0" prefWidth="300.0">
          <statistics>
             <FXCollections fx:factory="observableArrayList" >
                 <String fx:value="employees"/>
                 <String fx:value="farms"/>
             </FXCollections>
           </statistics>
       </StepChart>
     </VBox>
  </Pane>

统计信息在 StepChart 中被标记为 @DefaultProperty,但为了完整性而包含在此处。在 StepChart 中,我选取可观察列表值,如下所示:

ArrayList<String> list = new ArrayList<String>();
ObservableList<String> statistics = FXCollections.observableArrayList(list);

statistics.addListener(new ListChangeListener<String>()
  {
     @Override
     public void onChanged(ListChangeListener.Change<? extends String> change)
     {         
        for(String s: statistics)
        {
           System.out.println("s: " +  s);
        }
     }
  });

一切都很完美,除了 fxml 生成的是单个字符串,而不是单独的字符串列表之外,其中包含 fxml 值:

s: [employees, farms]

尽管Introduction to fxml说它“创建一个可观察数组列表的实例,填充三个字符串值”。我是否遗漏了有关如何处理可观察列表的信息,或者这是预期的行为?

最佳答案

我怀疑你的StepChart类没有 setStatistics(...)方法。 FXMLLoader会以特殊的方式处理这个问题,如下:

通常,当 FXMLLoader遇到这样的结构:

<ClassName fx:id="ref">
  <propertyName>
     <AnotherClass />
  </propertyName>
</ClassName>

它执行的代码会转换为以下内容:

ClassName ref = new ClassName();
ref.setPropertyName(new AnotherClass());

(不是字面上的意思,它执行等效操作,但使用反射)。

在大多数情况下,如果没有 setPropertyName(...)定义在指定的类中,将会抛出异常。

只读列表被视为特殊情况:所以 if ClassName定义了 List getList() {...}方法,没有 void setList(List aList) {...}方法,那么以下仍然有效:

<ClassName fx:id="ref">
   <list>
      <!-- values -->
   </list>
</ClassName>

处理这种情况的方式,在这种特殊情况下(属性的名称对应于 List 类型的属性,有 get 方法,但没有 set 方法),然后是 FXMLLoader执行以下伪代码:

ClassName ref = new ClassName();
for (Object item : itemsDefinedInsideListElement) {
    ref.getList().add(item);
}

其中 for循环迭代 <list> 中定义的所有元素元素。这使您能够做类似的事情

<HBox>
  <children>
    <Label/>
    <TextField/>
  </children>
</HBox>

尽管HBox没有setChildren()方法。

因此,对于您的 FXML,假设 StepChart没有setStatistics(...)方法,FXMLLoader迭代 <statistics> 的所有直接子元素,将每一个传递给 getStatistics().add(...)StepChart 上调用它创建的实例。在这种情况下,只有一个子元素,即 ObservableList<String> .

FXMLLoader也足够聪明,可以在运行时计算列表的通用类型(我实际上不知道它是如何做到这一点的)。因为它看到列表期待 String ,并且该元素未解析为 String ,它尝试将其强制为正确的类型。强制为 String很简单:它只需要调用 toString因此,您最终会得到一个包含单个 String 的列表。 :那个String是调用 toString 的结果在List上包含元素“雇员”和“农场”。等效的 Java 代码类似于

StepChart employment = new StepChart();
employment.getStatistics().add(Arrays.asList("employees", "farms").toString());

因此您会看到单个元素 "["employees", "farms"]"作为 statistics 的内容.

对此您有两个修复方案,您选择的修复方案应取决于您想要在 StepChart 中公开的 API 。您可以添加 setStatistics(ObservableList<String>)方法。然后FXMLLoader将创建列表,并将其传递给该方法。

或者,您可以继续省略 setStatistics(...)方法(即保留 statistics 作为只读列表属性)并将 FXML 修改为

  <StepChart fx:id="employment"  ... >
      <statistics>
         <String fx:value="employees"/>
         <String fx:value="farms"/>
       </statistics>
   </StepChart>

以便您使用FXMLLoader的只读列表属性机制。

关于java - 从 fxml 实例化的 ObservableArrayList 返回值不符合预期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26614677/

相关文章:

javafx-2 - 在JavaFX2.2中,如何设置输入字段和表格标题中输入的文本的字体大小?

java - 使用 javafx 从 webview 获取打印

javafx - 在 Java 9 或 10 中创建 FXML 成员的正确做法是什么?

java - 创建具有不同样式的大量文本 - JavaFX FXML

java - java中如何选择设计模式

java - Magnolia v6.2 Atmosphere 无法配置 JSR-356

java - Lucene 禁止了不应该出现的子句 "fuzzyfied"

java - Spring AOP - 实现 spring aop 时不调用服务方法

java - 在 JavaFx 中为 GridPane 设置标签

java - 如何使用Java播放MP3文件?