添加 FXML 中定义的元素以循环列出
adding elements defined in FXML to list with loop
我有很多名称为 a1、a2、a3 的对象...
我需要将它们放入列表中,以便使用它们更简单,我会以某种方式使用循环来完成吗?
我的尝试是:
List<SomeObject> list = new LinkedList<SomeObject>();
for (int i=0; i<1000; i++){
String varName = "a"+i;
list.add((SomeObject) varName);
}
对于这种情况,有人有什么建议吗?
在循环内创建变量不是解决方案,因为它们是 .fxml 文档的一部分。
或者给我一个如何使用循环创建它的建议,因为它在 .fxml 中创建行与在循环中添加新对象并行。
为了更易于理解,.fxml 文件看起来像
<SomeObject fx:id="a1" *other props* />
<SomeObject fx:id="a2" *other props* />
<SomeObject fx:id="a3" *other props* />
<SomeObject fx:id="a4" *other props* />
多谢指教!
您可能更愿意将您的对象直接放入 fxml 的列表中:
<fx:define>
<FXCollections fx:id="theList" fx:factory="observableArrayList">
<SomeObject someProperty="SomeValue 1" />
<SomeObject someProperty="SomeValue 2" />
<SomeObject someProperty="SomeValue 3" />
<SomeObject someProperty="SomeValue 4" />
</FXCollections>
</fx:define>
并在控制器中访问它:
@FXML
private ObservableList<SomeObject> theList;
@Override
public void initialize( URL url, ResourceBundle rb )
{
// do whatever with the list
System.out.println( "the list of some objects = " + theList);
}
如果您不单独访问每个 SomeObject,您可以为它们删除 fx:id
s。有关 fxml 功能的更多信息,请参阅 Introduction to FXML.
如果您有那么多项目,最好使用 Java 初始化它们,而不是使用 FXML。例如,而不是:
<FlowPane fx:id="container" minWidth="..." minHeight="...">
<Label fx:id="label1" text="Label 1"/>
<Label fx:id="label2" text="Label 2"/>
<Label fx:id="label3" text="Label 3"/>
<!-- ... -->
<Label fx:id="label1000" text="Label 1000"/>
</FlowPane>
和一个控制器
public class Controller {
@FXML
private FlowPane container ;
@FXML
private Label label1 ;
@FXML
private Label label2 ;
// ...
@FXML
private Label label1000 ;
// ...
}
我愿意
<FlowPane fx:id="container" minWidth="..." minHeight="...">
</FlowPane>
和
public class Controller {
@FXML
private FlowPane container ;
private List<Label> labels ;
public void initialize() {
labels = new ArrayList<>();
for (int i = 1; i <= 1000; i++) {
Label label = new Label("Label "+i);
labels.add(label);
container.getChildren().add(label);
}
}
}
作为这个想法的变体,考虑定义一个自定义组件:
public class LabelFlow extends FlowPane {
private List<Label> labels ;
public LabelFlow(@NamedArg("numLabels") int numLabels) {
labels = new ArrayList<>();
for(int i = 1 ; i <= numLabels ; i++) {
Label label = new Label("Label "+i);
labels.add(label);
}
getChildren().addAll(labels);
}
public List<Label> getLabels() {
return Collections.unmodifiableList(labels);
}
}
现在在您的 FXML 中您可以
<LabelFlow fx:id="labelFlow" numLabels="1000"/>
并在您的控制器中
public class Controller {
@FXML
private LabelFlow labelFlow ;
public void initialize() {
for (Label label : labelFlow.getLabels()) {
// do whatever you need with label....
}
}
}
如果您想像 Scene Builder 中那样使用自定义 class,则需要跳过几个步骤。参见
如果您真的想要在 FXML 中定义所有这些控件,在我看来这将是一场维护噩梦,您可以使用反射来访问变量。我不推荐这样做,不仅因为它难以维护,还因为反射本质上是容易出错的(没有编译时检查)和复杂。
但你可以做到
public class Controller {
@FXML
private FlowPane container ;
@FXML
private Label label1 ;
@FXML
private Label label2 ;
// ...
@FXML
private Label label1000 ;
private List<Label> labels ;
public void initialize() throws Exception {
labels = new ArrayList<>();
for (int i = 1; i <= 1000; i++) {
Field field = getClass().getDeclaredField("label"+i);
boolean wasAccessible = field.isAccessible();
field.setAccessible(true);
Label label = (Label) field.get(this);
field.setAccessible(wasAccessible);
labels.add(label);
}
}
}
我个人更喜欢另一种可能性,但只是为了完整起见:
您还可以在加载后通过 fx:id
属性访问 FXMLLoader
创建的 Object
s,使用 FXMLLoader.getNamespace()
:
例子
namespace.fxml
<AnchorPane xmlns:fx="http://javafx.com/fxml/1">
<children>
<Text fx:id="node1" text="42"/>
</children>
</AnchorPane>
正在加载
FXMLLoader loader = new FXMLLoader(getClass().getResource("namespace.fxml"));
loader.load();
System.out.println(((Text)loader.getNamespace().get("node1")).getText());
打印 fxml 中 Text
元素的文本(即 42
)。
当然你不能在控制器中默认访问 FXMLLoader
实例,这意味着使用这种方法你需要自己将信息传递给控制器,如果那里需要的话。
我有很多名称为 a1、a2、a3 的对象... 我需要将它们放入列表中,以便使用它们更简单,我会以某种方式使用循环来完成吗?
我的尝试是:
List<SomeObject> list = new LinkedList<SomeObject>();
for (int i=0; i<1000; i++){
String varName = "a"+i;
list.add((SomeObject) varName);
}
对于这种情况,有人有什么建议吗? 在循环内创建变量不是解决方案,因为它们是 .fxml 文档的一部分。 或者给我一个如何使用循环创建它的建议,因为它在 .fxml 中创建行与在循环中添加新对象并行。
为了更易于理解,.fxml 文件看起来像
<SomeObject fx:id="a1" *other props* />
<SomeObject fx:id="a2" *other props* />
<SomeObject fx:id="a3" *other props* />
<SomeObject fx:id="a4" *other props* />
多谢指教!
您可能更愿意将您的对象直接放入 fxml 的列表中:
<fx:define>
<FXCollections fx:id="theList" fx:factory="observableArrayList">
<SomeObject someProperty="SomeValue 1" />
<SomeObject someProperty="SomeValue 2" />
<SomeObject someProperty="SomeValue 3" />
<SomeObject someProperty="SomeValue 4" />
</FXCollections>
</fx:define>
并在控制器中访问它:
@FXML
private ObservableList<SomeObject> theList;
@Override
public void initialize( URL url, ResourceBundle rb )
{
// do whatever with the list
System.out.println( "the list of some objects = " + theList);
}
如果您不单独访问每个 SomeObject,您可以为它们删除 fx:id
s。有关 fxml 功能的更多信息,请参阅 Introduction to FXML.
如果您有那么多项目,最好使用 Java 初始化它们,而不是使用 FXML。例如,而不是:
<FlowPane fx:id="container" minWidth="..." minHeight="...">
<Label fx:id="label1" text="Label 1"/>
<Label fx:id="label2" text="Label 2"/>
<Label fx:id="label3" text="Label 3"/>
<!-- ... -->
<Label fx:id="label1000" text="Label 1000"/>
</FlowPane>
和一个控制器
public class Controller {
@FXML
private FlowPane container ;
@FXML
private Label label1 ;
@FXML
private Label label2 ;
// ...
@FXML
private Label label1000 ;
// ...
}
我愿意
<FlowPane fx:id="container" minWidth="..." minHeight="...">
</FlowPane>
和
public class Controller {
@FXML
private FlowPane container ;
private List<Label> labels ;
public void initialize() {
labels = new ArrayList<>();
for (int i = 1; i <= 1000; i++) {
Label label = new Label("Label "+i);
labels.add(label);
container.getChildren().add(label);
}
}
}
作为这个想法的变体,考虑定义一个自定义组件:
public class LabelFlow extends FlowPane {
private List<Label> labels ;
public LabelFlow(@NamedArg("numLabels") int numLabels) {
labels = new ArrayList<>();
for(int i = 1 ; i <= numLabels ; i++) {
Label label = new Label("Label "+i);
labels.add(label);
}
getChildren().addAll(labels);
}
public List<Label> getLabels() {
return Collections.unmodifiableList(labels);
}
}
现在在您的 FXML 中您可以
<LabelFlow fx:id="labelFlow" numLabels="1000"/>
并在您的控制器中
public class Controller {
@FXML
private LabelFlow labelFlow ;
public void initialize() {
for (Label label : labelFlow.getLabels()) {
// do whatever you need with label....
}
}
}
如果您想像 Scene Builder 中那样使用自定义 class,则需要跳过几个步骤。参见
如果您真的想要在 FXML 中定义所有这些控件,在我看来这将是一场维护噩梦,您可以使用反射来访问变量。我不推荐这样做,不仅因为它难以维护,还因为反射本质上是容易出错的(没有编译时检查)和复杂。
但你可以做到
public class Controller {
@FXML
private FlowPane container ;
@FXML
private Label label1 ;
@FXML
private Label label2 ;
// ...
@FXML
private Label label1000 ;
private List<Label> labels ;
public void initialize() throws Exception {
labels = new ArrayList<>();
for (int i = 1; i <= 1000; i++) {
Field field = getClass().getDeclaredField("label"+i);
boolean wasAccessible = field.isAccessible();
field.setAccessible(true);
Label label = (Label) field.get(this);
field.setAccessible(wasAccessible);
labels.add(label);
}
}
}
我个人更喜欢另一种可能性,但只是为了完整起见:
您还可以在加载后通过 fx:id
属性访问 FXMLLoader
创建的 Object
s,使用 FXMLLoader.getNamespace()
:
例子
namespace.fxml
<AnchorPane xmlns:fx="http://javafx.com/fxml/1">
<children>
<Text fx:id="node1" text="42"/>
</children>
</AnchorPane>
正在加载
FXMLLoader loader = new FXMLLoader(getClass().getResource("namespace.fxml"));
loader.load();
System.out.println(((Text)loader.getNamespace().get("node1")).getText());
打印 fxml 中 Text
元素的文本(即 42
)。
当然你不能在控制器中默认访问 FXMLLoader
实例,这意味着使用这种方法你需要自己将信息传递给控制器,如果那里需要的话。