JavaFX - 组合框中的嵌套列表

时间:2014-06-23 05:38:09

标签: listview binding combobox javafx nested-lists

如何将嵌套员工的主管列表绑定到JavaFX 8中的单个组合框。

我与员工和主管有以下简单的类结构:

public class Employee 
{
    private final StringProperty nameProperty = new SimpleStringProperty();

    public Employee(String name)
    {
        this.nameProperty.set(name);
    }

    public StringProperty nameProperty()
    {
        return this.nameProperty;
    }
}

public class Supervisor 
{
    private final StringProperty nameProperty = new SimpleStringProperty();
    private final ListProperty<Employee> employeesProperty = new SimpleListProperty<Employee>();

    public Supervisor(String name, List<Employee> employees)
    {
        this.nameProperty.set(name);
        this.employeesProperty.addAll(employees);
    }

    public StringProperty nameProperty()
    {
        return this.nameProperty;
    }

    public ListProperty<Employee> employeesProperty()
    {
        return this.employeesProperty;
    }
}

最后是一个简单的静态Supervisor类:

public static class Supervisors
{
    private static final ListProperty<Supervisor> supervisorsProperty = new SimpleListProperty<Supervisor>();

    public static ListProperty<Supervisor> supervisorsProperty()
    {
        return supervisorsProperty;
    }
}

(此示例的代码已经简化)

现在,我的问题是:

如何将主管列表绑定到JavaFX组合框(或列表视图,差异不应该重要)?我想&#34;展开&#34;员工列表,以便组合框项目如下所示:

Supervisor A
Employee A.1
Employee A.2
Supervisor B
Employee B.1

如果我只是将combobox.itemsProperty绑定到Supervisors.supervisorsProperty,那么我只会获得主管列表,而不是员工。

注意:我正在使用绑定,因此添加或删除主管或员工将直接反映在组合框中。

我是否使用特殊绑定或使用某种适配器类来展开&#34;展开&#34;将嵌套列表放入一个主管和员工列表中?如果是后者,那么我如何跟踪监督者列表(和嵌套员工)的变化,以及如何防止变为注册和未注册的变更登记者的复杂混乱?

PS:如果答案包含总是在组合框中显示主管/员工的正确名称的方式,那么有一个神奇的独角兽奖励积分 - 这样如果更改了名称,那么名称也会在组合框中更改

1 个答案:

答案 0 :(得分:0)

我最终自己制作了糟糕而复杂的解决方案。

我为Supervisor和Employee添加了一个基类:

public abstract class NamedInstance {
    private final StringProperty nameProperty = new SimpleStringProperty();

    public NamedInstance(String name)
    {
        this.nameProperty.set(name);
    }

    public StringProperty nameProperty()
    {
        return nameProperty;
    }

    public String getName()
    {
        return nameProperty.get();
    }

    @Override
    public String toString() {
        return getName();
    }
}

toString()将自动在ComboBox列表中使用。

然后我添加了这个糟糕的适配器类,用于制作嵌套的“带有员工的主管”结构的平面列表版本。在嵌套列表中添加或删除主管或员工时,平面列表将自动更改:

public class SupervisorsAndEmployeesList
{
    // the flat list of supervisors and employees
    private final ListProperty<NamedInstance> supervisorsAndEmployees = new SimpleListProperty<NamedInstance>(FXCollections.observableArrayList());
    // a ChangeListener for changes in a list of Employees
    private final ChangeListener<ObservableList<Employee>> employeeChangeListener = new ChangeListener<ObservableList<Employee>>()
    {
        @Override
        public void changed(ObservableValue<? extends ObservableList<Employee>> observable,
                ObservableList<Employee> oldValue, ObservableList<Employee> newValue) 
        {
            refreshList();
        }

    };

    public SupervisorsAndEmployeesList()
    {
        // add a ChangeListener for changes in the list of Supervisors
        Supervisors.supervisorsProperty().addListener(new ChangeListener<ObservableList<Supervisor>>() 
        {
            @Override
            public void changed(
                    ObservableValue<? extends ObservableList<Supervisor>> observable,
                    ObservableList<Supervisor> oldValue,
                    ObservableList<Supervisor> newValue)
            {
                // make sure to have listeners on each employee, and to remove the listeners 
                // again when supervisors are removed
                for (Supervisor supervisor : oldValue)
                {
                    supervisor.employeesProperty().removeListener(employeeChangeListener);
                }
                for (Supervisor supervisor : newValue)
                {
                    supervisor.employeesProperty().addListener(employeeChangeListener);
                }
                refreshList();
            }
        });
    }

    private void refreshList() 
    {
        // clear the list and re-add all Supervisors and Employees. 
        // this is not effective, but more readable than keeping track 
        // a each change in the list
        supervisorsAndEmployees.clear();
        for (Supervisor supervisor : Supervisors.supervisorsProperty().get())
        {
            supervisorsAndEmployees.add(supervisor);
            for (Employee employee : supervisor.employeesProperty().get())
            {
                supervisorsAndEmployees.add(employee);
            }
        }
    }

    public ListProperty<NamedInstance> supervisorsAndEmployeesProperty()
    {
        return supervisorsAndEmployees;
    }
}

ComboBox项目设置如下:

supervisorsAndEmployeesComboBox.setItems(new SupervisorsAndEmployeesList().supervisorsAndEmployeesProperty().get()); 

处理这样一项任务的代码很多......

我还解决了在ComboBox中的名称发生更改的问题,然后Supervisor或Employee名称发生了变化,但我没有在上面包含该代码,因为这会使代码更加复杂和难以理解。通常,您只需“添加”一个“nameChangeListener”到每个Supervisor和Employee的nameProperty(记得也像删除employeeChangeListener一样删除监听器)。每次调用nameChangeListener时,都会调用“refreshList()”。