JavaFX组合框绑定

JavaFX组合框绑定,javafx,Javafx,假设我有两个模型。老师和学生,每个学生可以有一个老师(不是几个)。所以我想在我的学生窗格上有一个组合框,在那里我可以选择一位老师 这两个模型也都存储在数据库中,我只希望教师的数据库ID在学生的模型中,但在组合框中应该显示教师的姓名 此外,模型应该绑定到组合框,因此如果有人在组合框中更改了教师,那么(学生的)模型也应该刷新。使用textfields,我可以将它们绑定到StringProperty对象,但在本例中,我需要将comboxbox项(Teacher.java)绑定到Student.java

假设我有两个模型。老师和学生,每个学生可以有一个老师(不是几个)。所以我想在我的学生窗格上有一个组合框,在那里我可以选择一位老师

这两个模型也都存储在数据库中,我只希望教师的数据库ID在学生的模型中,但在组合框中应该显示教师的姓名

此外,模型应该绑定到组合框,因此如果有人在组合框中更改了教师,那么(学生的)模型也应该刷新。使用textfields,我可以将它们绑定到StringProperty对象,但在本例中,我需要将comboxbox项(Teacher.java)绑定到Student.java中的integer属性

我还考虑将教师模型作为学生类中的属性,但我认为这不会有帮助,因为这样我需要在学生模型中用教师对象绑定combobox项(teacher.java),但只能绑定属性对象

Teacher.java

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Teacher {

    private Integer databaseID;

    private StringProperty name = new SimpleStringProperty();

    private IntegerProperty age = new SimpleIntegerProperty();


    public Teacher (Integer databaseID) {
        // load data from database and fill into model
    }

    public void store() {
        // write model to database
    }

    // getters and setters ...

    @Override
    public String toString() {
        return name.get();
    }

    @Override
    public boolean equals(Object obj) {
        // compare databaseIDs ...
        return true;
    }
}
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Student {

    private Integer databaseID;

    private StringProperty name = new SimpleStringProperty();

    private Integer teacherID;


    public Student (Integer databaseID) {
        // load data from database and fill into model
    }

    public void store() {
        // write model to database
    }

    // getters and setters ...

    @Override
    public String toString() {
        return name.get();
    }

    @Override
    public boolean equals(Object obj) {
        // compare databaseIDs ...
        return true;
    }
}
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class TestApplication extends Application {

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

    @Override
    public void start(Stage primaryStage) {

        Student student = new Student(4711);

        ComboBox<Teacher> teachers = new ComboBox<Teacher>();
        fillTeacherComboBox(teachers);

        // TODO: select the teacher from the student by default

        // FIXME: Binding student.databaseID <--> ComboBox-Item.databaseID


        StackPane root = new StackPane();
        root.getChildren().add(teachers);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }

    private void fillTeacherComboBox(ComboBox<Teacher> teachers) {
        // TODO: Load data from database and fill teacher combo box
    }


}
Student.java

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Teacher {

    private Integer databaseID;

    private StringProperty name = new SimpleStringProperty();

    private IntegerProperty age = new SimpleIntegerProperty();


    public Teacher (Integer databaseID) {
        // load data from database and fill into model
    }

    public void store() {
        // write model to database
    }

    // getters and setters ...

    @Override
    public String toString() {
        return name.get();
    }

    @Override
    public boolean equals(Object obj) {
        // compare databaseIDs ...
        return true;
    }
}
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Student {

    private Integer databaseID;

    private StringProperty name = new SimpleStringProperty();

    private Integer teacherID;


    public Student (Integer databaseID) {
        // load data from database and fill into model
    }

    public void store() {
        // write model to database
    }

    // getters and setters ...

    @Override
    public String toString() {
        return name.get();
    }

    @Override
    public boolean equals(Object obj) {
        // compare databaseIDs ...
        return true;
    }
}
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class TestApplication extends Application {

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

    @Override
    public void start(Stage primaryStage) {

        Student student = new Student(4711);

        ComboBox<Teacher> teachers = new ComboBox<Teacher>();
        fillTeacherComboBox(teachers);

        // TODO: select the teacher from the student by default

        // FIXME: Binding student.databaseID <--> ComboBox-Item.databaseID


        StackPane root = new StackPane();
        root.getChildren().add(teachers);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }

    private void fillTeacherComboBox(ComboBox<Teacher> teachers) {
        // TODO: Load data from database and fill teacher combo box
    }


}
Application.java

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Teacher {

    private Integer databaseID;

    private StringProperty name = new SimpleStringProperty();

    private IntegerProperty age = new SimpleIntegerProperty();


    public Teacher (Integer databaseID) {
        // load data from database and fill into model
    }

    public void store() {
        // write model to database
    }

    // getters and setters ...

    @Override
    public String toString() {
        return name.get();
    }

    @Override
    public boolean equals(Object obj) {
        // compare databaseIDs ...
        return true;
    }
}
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Student {

    private Integer databaseID;

    private StringProperty name = new SimpleStringProperty();

    private Integer teacherID;


    public Student (Integer databaseID) {
        // load data from database and fill into model
    }

    public void store() {
        // write model to database
    }

    // getters and setters ...

    @Override
    public String toString() {
        return name.get();
    }

    @Override
    public boolean equals(Object obj) {
        // compare databaseIDs ...
        return true;
    }
}
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class TestApplication extends Application {

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

    @Override
    public void start(Stage primaryStage) {

        Student student = new Student(4711);

        ComboBox<Teacher> teachers = new ComboBox<Teacher>();
        fillTeacherComboBox(teachers);

        // TODO: select the teacher from the student by default

        // FIXME: Binding student.databaseID <--> ComboBox-Item.databaseID


        StackPane root = new StackPane();
        root.getChildren().add(teachers);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }

    private void fillTeacherComboBox(ComboBox<Teacher> teachers) {
        // TODO: Load data from database and fill teacher combo box
    }


}
导入javafx.application.application;
导入javafx.scene.scene;
导入javafx.scene.control.ComboBox;
导入javafx.scene.layout.StackPane;
导入javafx.stage.stage;
公共类TestApplication扩展了应用程序{
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公共无效开始(阶段primaryStage){
学生=新生(4711);
ComboBox教师=新建ComboBox();
填写教师组合框(教师);
//TODO:默认情况下,从学生中选择教师
//修复方法:绑定student.databaseID组合框-Item.databaseID
StackPane root=新的StackPane();
root.getChildren().add(教师);
原始阶段。设置场景(新场景(根,300250));
primaryStage.show();
}
私人空白填充教师组合框(组合框教师){
//TODO:从数据库加载数据并填充教师组合框
}
}
我将(至少)对此处的设计进行一次更改:在
Student
对象中存储对
Teacher
对象的引用(并使用JavaFX属性执行此操作):

公共班级学生{
私有整数数据库ID;
私有StringProperty名称=新的SimpleStringProperty();
私有ObjectProperty教师=新的SimpleObjectProperty();
公立学生(整数数据库ID){
//从数据库加载数据并填充到模型中
/*顺便说一句,包括在内真的是一种糟糕的做法
如您在此处所建议的,域对象中的数据库代码。
您应该创建一个单独的类来管理数据库
代码(DataAccessObject)和域对象,以及
教师应该完全不可知的机制
它们是否被持久化(甚至是否被持久化)*/
}
公共仓库(){
//将模型写入数据库
//见上述评论。
}
//接球手和接球手。。。
公共对象属性教师属性(){
归国教师;
}
公共期末教师getTeacher(){
返回teacherProperty().get();
}
公开最终无效设置教师(教师){
teacherProperty().set(教师);
}
@凌驾
公共字符串toString(){
返回name.get();
}
@凌驾
公共布尔等于(对象obj){
//比较数据库ID。。。
返回true;
}
}
现在你就这么做了

Student student = ... ;
ComboBox<Teacher> teachers = new ComboBox<>();
// populate combo box...
teachers.valueProperty().bindBidirectional(student.teacherProperty());
Student学生=;
ComboBox教师=新建ComboBox();
//填充组合框。。。
teachers.valueProperty().bind(student.teacherProperty());
您可以尝试以下方法之一:(为我工作)


当第一个变化,第二个变化和诗句发生时,我知道这很奇怪,我不知道是否有解释(它的工作原理类似于BindBiodary())

当我在这里使用bind()时,在更改第一个值之前,我无法更改2d one值


(我认为2d one值在您设置之前不会更改,但如果单击列表中的新项,我不知道为什么不更改)。如果有人能回答这些问题,我希望他能写出来。

“我只希望老师的数据库ID是学生的模型。”。你为什么要那样?为什么不在学生的模型中引用老师?这能解决问题吗?我还考虑将教师模型作为学生类中的属性,但我认为这不会有帮助,因为这样我需要在学生模型中用教师对象绑定combobox项(teacher.java),但只能绑定属性对象。这样做会更容易。当然,“只能绑定属性对象”的解决方案是在
学生
教师
类中使用JavaFX属性?看来这是不可能的。其他人通过使用changelistener来实现这一点,并在changelistener中将所选的教师模型设置为学生模型。这不是很好,但很有效。也许其他人有更好的主意?为什么不可能呢?这个建议的问题是,它意味着巨大的代码重复-对于我现在必须使用的每个数据模型类-一个用于DB/持久性,一个用于UI。除非我误解了你在
学生的构造函数中的评论。是的,我想你误解了这个评论。DAO只管理实体的持久性(保存和从数据库加载)。实体没有重复(持久性代码也没有)。啊,我明白了。那么您有一个模型类,它具有可观察性和JavaFX属性,DAO将其保存并从持久性层加载到持久性层?我想这意味着在UI范围之外的类上使用JavaFX属性没有明显的缺点吗?有些人可能会认为附加的API依赖性是不利的,但是IM