类似于 xaml 的 JavaFX8 列表绑定
JavaFX8 list bindings similar to xaml
我无法在 fxml 中将集合绑定到自定义模板。这是我在 xaml:
中的代码
<ListView ItemsSource="{Binding PersonCollection}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding FirstName}"></Label>
<ListView ItemsSource="{Binding MiddleNames}">
<Label Content="{Binding}"></Label>
</ListView>
<Label Content="{Binding LastName}"></Label>
</StackPanel>
</ListView>
这里是模型:
class Person
{
String FirstName, LastName;
String[] MiddleNames;
}
布局看起来类似于:
John Ivy
Robert Downey Junior
Max more middlenames in fact even thousands are possible lastname
是否可以将可观察集合绑定到自定义模板?
我尝试了 cellfactory,但无法理解它,因为每个人都只使用字符串。
我不是 100% 确定这是您问题的答案,因为我完全不熟悉 xaml,但希望它是...
示例实现
示例通过将模型对象(Person)设置到 FXML 加载器的命名空间中来工作,这允许您使用 FXML 中的绑定表达式绑定到对象的属性。
在示例中,模型中最初有几个名称,您可以使用添加和删除按钮修改模型中的绑定列表,以在列表中添加或删除更多固定名称。
所有代码都放在名为 sample.names 的包中。
姓名-display.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Button?>
<VBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.names.NameDisplayController">
<HBox prefHeight="150.0" prefWidth="220.0" spacing="5.0" >
<children>
<Label fx:id="firstNameLabel" text="${person.firstName}" />
<ListView fx:id="middleNameList" prefWidth="100.0" items = "${person.middleNames}" />
<Label fx:id="lastNameLabel" text="${person.lastName}" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</HBox>
<HBox alignment="CENTER" spacing="30.0">
<children>
<Button mnemonicParsing="false" onAction="#addName" text="Add" />
<Button mnemonicParsing="false" onAction="#removeName" text="Remove" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</HBox>
</VBox>
NameDisplayApp.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import java.io.IOException;
public class NameDisplayApp extends Application {
@Override
public void start(Stage stage) throws IOException {
Person person = new Person(
"Bruce",
new String[] { "Simon", "Larry" },
"Banner"
);
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"name-display.fxml"
)
);
loader.getNamespace().put(
"person",
person
);
Pane pane = loader.load();
NameDisplayController controller = loader.getController();
controller.setPerson(person);
stage.setScene(new Scene(pane));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
NameDisplayController.java
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
public class NameDisplayController {
private Person person;
private ObservableList<String> sampleNames = FXCollections.observableArrayList(
"George", "Henry", "Wallace"
);
public void setPerson(Person person) {
this.person = person;
}
public void addName(ActionEvent actionEvent) {
if (!sampleNames.isEmpty()) {
person.getMiddleNames().add(
sampleNames.remove(0)
);
}
}
public void removeName(ActionEvent actionEvent) {
if (!person.getMiddleNames().isEmpty()) {
sampleNames.add(
person.getMiddleNames().remove(0)
);
}
}
}
Person.java
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class Person {
public StringProperty firstName;
public StringProperty lastName;
private ObservableList<String> middleNames;
public Person(String firstName, String[] middleNames, String lastName) {
this.firstName = new SimpleStringProperty(firstName);
this.middleNames = FXCollections.observableArrayList(middleNames);
this.lastName = new SimpleStringProperty(lastName);
}
public String getFirstName() {
return firstName.get();
}
public StringProperty firstNameProperty() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public ObservableList<String> getMiddleNames() {
return middleNames;
}
public String getLastName() {
return lastName.get();
}
public StringProperty lastNameProperty() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
}
替代实现
可能还有其他(也许更优选的方式)可以做到这一点 - 例如通过关联代码中项目的绑定而不是 FXML(这是我通常做的)或使用依赖注入系统注入模型。有关注入方法的示例,请参阅 afterburner.fx - 虽然我不知道加力器是否也将模型对象放入 FXML 命名空间或仅注入控制器(如果它不注入到 FXML 命名空间)可能是一个很酷的补充,你可以要求它)。
我无法在 fxml 中将集合绑定到自定义模板。这是我在 xaml:
中的代码<ListView ItemsSource="{Binding PersonCollection}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding FirstName}"></Label>
<ListView ItemsSource="{Binding MiddleNames}">
<Label Content="{Binding}"></Label>
</ListView>
<Label Content="{Binding LastName}"></Label>
</StackPanel>
</ListView>
这里是模型:
class Person
{
String FirstName, LastName;
String[] MiddleNames;
}
布局看起来类似于:
John Ivy
Robert Downey Junior
Max more middlenames in fact even thousands are possible lastname
是否可以将可观察集合绑定到自定义模板? 我尝试了 cellfactory,但无法理解它,因为每个人都只使用字符串。
我不是 100% 确定这是您问题的答案,因为我完全不熟悉 xaml,但希望它是...
示例实现
示例通过将模型对象(Person)设置到 FXML 加载器的命名空间中来工作,这允许您使用 FXML 中的绑定表达式绑定到对象的属性。
在示例中,模型中最初有几个名称,您可以使用添加和删除按钮修改模型中的绑定列表,以在列表中添加或删除更多固定名称。
所有代码都放在名为 sample.names 的包中。
姓名-display.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Button?>
<VBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.names.NameDisplayController">
<HBox prefHeight="150.0" prefWidth="220.0" spacing="5.0" >
<children>
<Label fx:id="firstNameLabel" text="${person.firstName}" />
<ListView fx:id="middleNameList" prefWidth="100.0" items = "${person.middleNames}" />
<Label fx:id="lastNameLabel" text="${person.lastName}" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</HBox>
<HBox alignment="CENTER" spacing="30.0">
<children>
<Button mnemonicParsing="false" onAction="#addName" text="Add" />
<Button mnemonicParsing="false" onAction="#removeName" text="Remove" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</HBox>
</VBox>
NameDisplayApp.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import java.io.IOException;
public class NameDisplayApp extends Application {
@Override
public void start(Stage stage) throws IOException {
Person person = new Person(
"Bruce",
new String[] { "Simon", "Larry" },
"Banner"
);
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"name-display.fxml"
)
);
loader.getNamespace().put(
"person",
person
);
Pane pane = loader.load();
NameDisplayController controller = loader.getController();
controller.setPerson(person);
stage.setScene(new Scene(pane));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
NameDisplayController.java
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
public class NameDisplayController {
private Person person;
private ObservableList<String> sampleNames = FXCollections.observableArrayList(
"George", "Henry", "Wallace"
);
public void setPerson(Person person) {
this.person = person;
}
public void addName(ActionEvent actionEvent) {
if (!sampleNames.isEmpty()) {
person.getMiddleNames().add(
sampleNames.remove(0)
);
}
}
public void removeName(ActionEvent actionEvent) {
if (!person.getMiddleNames().isEmpty()) {
sampleNames.add(
person.getMiddleNames().remove(0)
);
}
}
}
Person.java
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class Person {
public StringProperty firstName;
public StringProperty lastName;
private ObservableList<String> middleNames;
public Person(String firstName, String[] middleNames, String lastName) {
this.firstName = new SimpleStringProperty(firstName);
this.middleNames = FXCollections.observableArrayList(middleNames);
this.lastName = new SimpleStringProperty(lastName);
}
public String getFirstName() {
return firstName.get();
}
public StringProperty firstNameProperty() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public ObservableList<String> getMiddleNames() {
return middleNames;
}
public String getLastName() {
return lastName.get();
}
public StringProperty lastNameProperty() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
}
替代实现
可能还有其他(也许更优选的方式)可以做到这一点 - 例如通过关联代码中项目的绑定而不是 FXML(这是我通常做的)或使用依赖注入系统注入模型。有关注入方法的示例,请参阅 afterburner.fx - 虽然我不知道加力器是否也将模型对象放入 FXML 命名空间或仅注入控制器(如果它不注入到 FXML 命名空间)可能是一个很酷的补充,你可以要求它)。