Java 如何将对象集的属性双向绑定到表视图的选定项属性?

Java 如何将对象集的属性双向绑定到表视图的选定项属性?,java,binding,javafx,javafx-8,Java,Binding,Javafx,Javafx 8,我的用户界面如下所示: 我想要的是,当你点击表中的1时,文本框会显示表中的2和3,它会显示4,当你在文本框中键入时,所选行绑定到的对象的属性会被更新 因此,我有一个具有两个属性的对象集合(value1-在表中,value2在文本框中) 现在讨论一下复杂性:我想用一个双向绑定,而不是一个事件侦听器来实现这一点 基本上,文本框的绑定可以这样描述: 将text属性双向绑定到表视图的selected item属性的value2属性 这有可能吗 我在四处摆弄,我做到了这一点,但这不是双向的,当然(我可能

我的用户界面如下所示:

我想要的是,当你点击表中的1时,文本框会显示表中的2和3,它会显示4,当你在文本框中键入时,所选行绑定到的对象的属性会被更新

因此,我有一个具有两个属性的对象集合(value1-在表中,value2在文本框中)

现在讨论一下复杂性:我想用一个双向绑定,而不是一个事件侦听器来实现这一点

基本上,文本框的绑定可以这样描述:

将text属性双向绑定到表视图的selected item属性的value2属性

这有可能吗

我在四处摆弄,我做到了这一点,但这不是双向的,当然(我可能需要提供第二次回调,以达到相反的方向):

下面是一个完整的工作示例,可以更清楚地说明我所说的内容:

import java.net.URL;
import java.util.ResourceBundle;

import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.stage.Stage;

public final class Program extends Application {

    private static final class SomeSortOfController implements Initializable {

        @FXML private TableView<SomeSortOfObject> tableView;
        @FXML private TableColumn<SomeSortOfObject, Number> value1TableColumn;
        @FXML private TextField textField;

        @Override
        public void initialize(final URL url, final ResourceBundle resourceBundle) {

            this.tableView.setItems(FXCollections.observableArrayList(
                    new SomeSortOfObject(1,2),
                    new SomeSortOfObject(3,4)));

            this.value1TableColumn.setCellValueFactory(c -> c.getValue().value1Property());
            this.value1TableColumn.setEditable(false);

            // Here I need to come up with some sort of binding from the selected item
            // in the table view to the value2 property in the SomeSortOfObject (and
            // vice versa)
        }
    }

    private static final class SomeSortOfObject {

        private final IntegerProperty value1;
        private final IntegerProperty value2;

        public SomeSortOfObject(int value1, int value2) {
            this.value1 = new SimpleIntegerProperty(value1);
            this.value2 = new SimpleIntegerProperty(value2);
        }

        public IntegerProperty value1Property() {
            return this.value1;
        }

        public IntegerProperty value2Property() {
            return this.value2;
        }
    }

    public static void main(final String[] args) {
        launch(args);
    }

    @Override
    public void start(final Stage stage) throws Exception {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/main.fxml"));
        loader.setController(new SomeSortOfController());   
        stage.setScene(new Scene(loader.load(), 200, 100));     
        stage.show();
    }
}
import java.net.URL;
导入java.util.ResourceBundle;
导入javafx.application.application;
导入javafx.beans.property.IntegerProperty;
导入javafx.beans.property.SimpleIntegerProperty;
导入javafx.collections.FXCollections;
导入javafx.fxml.fxml;
导入javafx.fxml.fxmloader;
导入javafx.fxml.Initializable;
导入javafx.scene.scene;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableView;
导入javafx.scene.control.TextField;
导入javafx.stage.stage;
公共期末课程扩展应用{
私有静态最终类SomeSortOfController实现可初始化{
@FXML私有表视图表视图;
@FXML私有表列值1表列;
@FXML私有文本字段文本字段;
@凌驾
公共void初始化(最终URL、最终ResourceBundle和ResourceBundle){
this.tableView.setItems(FXCollections.observableArrayList(
新SomeSortOfObject(1,2),
新的SomeSortOfObject(3,4));
此.value1TableColumn.setCellValueFactory(c->c.getValue().value1Property());
此.value1TableColumn.setEditable(false);
//在这里,我需要从所选项目中找到某种绑定
//在表视图中,指向SomeSortOfObject中的value2属性(和
//反之亦然)
}
}
私有静态最终类SomeSortOfObject{
私有最终整数属性值1;
私有最终集成属性值2;
公共SomeSortOfObject(int值1、int值2){
this.value1=新的SimpleIntegerProperty(value1);
this.value2=新的SimpleIntegerProperty(value2);
}
公共整数属性值1属性(){
返回此值。1;
}
公共整数属性值2属性(){
返回此值。2;
}
}
公共静态void main(最终字符串[]args){
发射(args);
}
@凌驾
public void start(final Stage)引发异常{
FXMLLoader=newFXMLLoader(getClass().getResource(“/main.fxml”);
setController(新的SomeSortOfController());
stage.setScene(新场景(loader.load(),200100));
stage.show();
}
}
为了完整起见,以下是main.fxml文件的内容:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<HBox xmlns="http://javafx.com/javafx/8.0.45" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <TableView fx:id="tableView">
        <columns>
          <TableColumn text="value1" fx:id="value1TableColumn" />
        </columns>
      </TableView>
      <TextField fx:id="textField" />
   </children>
</HBox>

没有标准的API方法可以做到这一点。有一些第三方库提供此功能。最著名的可能是,这个库可能会在版本9中被合并到JavaFX中

下面是一个使用EasyBind的SSCCE:

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.monadic.PropertyBinding;

public class BidirectionalBindingToNestedProperty extends Application {

    private PropertyBinding<String> selectedValue2;

    @Override
    public void start(Stage primaryStage) {
        TableView<Item> table = new TableView<>();
        TableColumn<Item, String> col1 = new TableColumn<>("Value 1");
        col1.setCellValueFactory(cellData -> cellData.getValue().value1Property());

        table.getColumns().add(col1);

        TextField textField = new TextField();
        selectedValue2 = EasyBind
                .monadic(table.getSelectionModel().selectedItemProperty())
                .selectProperty(Item::value2Property);
        textField.textProperty().bindBidirectional(selectedValue2);

        for (int i = 1 ; i <= 40; i+=2) {
            Item item = new Item(String.valueOf(i), String.valueOf(i + 1));
            item.value2Property().addListener((obs, oldValue, newValue) -> 
                System.out.println("Item with value1 = "+item.getValue1() + " changed value2 from "+oldValue+" to "+newValue));
            table.getItems().add(item);
        }

        BorderPane root = new BorderPane(table, null, null, null, textField);

        Scene scene = new Scene(root, 800, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static class Item {
        private final StringProperty value1 = new SimpleStringProperty();
        private final StringProperty value2 = new SimpleStringProperty();

        public Item(String value1, String value2) {
            setValue1(value1);
            setValue2(value2);
        }

        public final StringProperty value1Property() {
            return this.value1;
        }

        public final java.lang.String getValue1() {
            return this.value1Property().get();
        }

        public final void setValue1(final java.lang.String value1) {
            this.value1Property().set(value1);
        }

        public final StringProperty value2Property() {
            return this.value2;
        }

        public final java.lang.String getValue2() {
            return this.value2Property().get();
        }

        public final void setValue2(final java.lang.String value2) {
            this.value2Property().set(value2);
        }


    }

    public static void main(String[] args) {
        launch(args);
    }
}
导入javafx.application.application;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.beans.property.StringProperty;
导入javafx.scene.scene;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableView;
导入javafx.scene.control.TextField;
导入javafx.scene.layout.BorderPane;
导入javafx.stage.stage;
导入org.fxmisc.easybind.easybind;
导入org.fxmisc.easybind.monadic.PropertyBinding;
公共类双向绑定属性扩展了应用程序{
私有财产绑定选定价值2;
@凌驾
公共无效开始(阶段primaryStage){
TableView table=新TableView();
TableColumn col1=新的TableColumn(“值1”);
col1.setCellValueFactory(cellData->cellData.getValue().value1Property());
table.getColumns().add(col1);
TextField TextField=新的TextField();
selectedValue2=轻松绑定
.monadic(table.getSelectionModel().selectedItemProperty())
.selectProperty(项目::value2Property);
textField.textProperty().bindBidirectional(selectedValue2);
对于(int i=1;i
System.out.println(“带值的项1=“+Item.getValue1()+”将值2从“+oldValue+”更改为“+newValue”);
table.getItems().add(item);
}
BorderPane root=新的BorderPane(表,null,null,null,textField);
场景=新场景(根,800600);
初级阶段。场景(场景);
primaryStage.show();
}
公共静态类项{
私有最终StringProperty值1=新的SimpleStringProperty();
私有最终StringProperty值2=新的SimpleStringProperty();
公共项(字符串值1、字符串值2){
设置值1(值1);
setValue2(value2);
}
公共最终字符串属性值1属性(){
返回此值。1;
}
public final java.lang.String getValue1(){
返回此.value1Property().get();
}
public final void setValue1(final java.lang.String值
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.monadic.PropertyBinding;

public class BidirectionalBindingToNestedProperty extends Application {

    private PropertyBinding<String> selectedValue2;

    @Override
    public void start(Stage primaryStage) {
        TableView<Item> table = new TableView<>();
        TableColumn<Item, String> col1 = new TableColumn<>("Value 1");
        col1.setCellValueFactory(cellData -> cellData.getValue().value1Property());

        table.getColumns().add(col1);

        TextField textField = new TextField();
        selectedValue2 = EasyBind
                .monadic(table.getSelectionModel().selectedItemProperty())
                .selectProperty(Item::value2Property);
        textField.textProperty().bindBidirectional(selectedValue2);

        for (int i = 1 ; i <= 40; i+=2) {
            Item item = new Item(String.valueOf(i), String.valueOf(i + 1));
            item.value2Property().addListener((obs, oldValue, newValue) -> 
                System.out.println("Item with value1 = "+item.getValue1() + " changed value2 from "+oldValue+" to "+newValue));
            table.getItems().add(item);
        }

        BorderPane root = new BorderPane(table, null, null, null, textField);

        Scene scene = new Scene(root, 800, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static class Item {
        private final StringProperty value1 = new SimpleStringProperty();
        private final StringProperty value2 = new SimpleStringProperty();

        public Item(String value1, String value2) {
            setValue1(value1);
            setValue2(value2);
        }

        public final StringProperty value1Property() {
            return this.value1;
        }

        public final java.lang.String getValue1() {
            return this.value1Property().get();
        }

        public final void setValue1(final java.lang.String value1) {
            this.value1Property().set(value1);
        }

        public final StringProperty value2Property() {
            return this.value2;
        }

        public final java.lang.String getValue2() {
            return this.value2Property().get();
        }

        public final void setValue2(final java.lang.String value2) {
            this.value2Property().set(value2);
        }


    }

    public static void main(String[] args) {
        launch(args);
    }
}