Подтвердить что ты не робот

Пара значений ключа для комбинированного поля в JavaFX 2

Я только начинаю изучать JavaFX 2.
Теперь я пытаюсь создать образец приложения. Затем я застрял в combobox.
Я не нашел ссылки на пару ключевых значений для combobox в JavaFX.
В combobox javadoc на http://docs.oracle.com/javafx/2/api/index.html не сказано много о паре значений ключа.

Как создать комбобокс с элементами, имеющими различное отображаемое значение и фактическое значение?

4b9b3361

Ответ 1

У вас есть 2 подхода:
1. Просто переопределите метод toString() в вашем классе datamodel. Пример:

public class Demo extends Application {

    private final ObservableList<Employee> data =
            FXCollections.observableArrayList(
            new Employee("Azamat", 2200.15),
            new Employee("Veli", 1400.0),
            new Employee("Nurbek", 900.5));

    @Override
    public void start(Stage primaryStage) {

        ComboBox<Employee> combobox = new ComboBox<>(data);
        combobox.getSelectionModel().selectFirst(); // Select first as default
        combobox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Employee>() {

            @Override
            public void changed(ObservableValue<? extends Employee> arg0, Employee arg1, Employee arg2) {
                if (arg2 != null) {
                    System.out.println("Selected employee: " + arg2.getName());
                }
            }
        });
        StackPane root = new StackPane();
        root.getChildren().add(combobox);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }

    public static class Employee {
        private String name;
        private Double salary;

        @Override
        public String toString() {
            return name + " (sal:" + salary + ")";
        }

        public Employee(String name, Double salary) {
            this.name = name;
            this.salary = salary;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Double getSalary() {
            return salary;
        }

        public void setSalary(Double salary) {
            this.salary = salary;
        }
    }

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

Обратите внимание на переопределение toString() класса Employee. Ключ combobox (фактическое значение) будет экземпляром Employee, и в этом случае отображаемое значение будет employee.toString().
2. Второй подход - установить свойство cellFactory в поле со списком.

combobox.setCellFactory(new Callback<ListView<Employee>, ListCell<Employee>>() {

    @Override
    public ListCell<Employee> call(ListView<Employee> arg0) {
        return new ListCell<Employee>() {

            private final Button btn;
            {
                setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
                btn = new Button();
            }

            @Override
            protected void updateItem(Employee item, boolean empty) {
                super.updateItem(item, empty);

                if (item == null || empty) {
                    setGraphic(null);
                } else {
                    btn.setStyle(item.getSalary() > 1000 ? "-fx-base:red" : "-fx-base: green");
                    btn.setText(item.getName() + "=" + item.getSalary());
                    setGraphic(btn);
                }
            }
        };
    }
});

Этот подход обеспечивает более мощный контроль над рендерингом ячейки. Вы не можете просто форматировать отображаемое значение, но также включать любой элемент node (control) в ячейку (кнопка в этом случае) и добавить некоторую логику просмотра (item.getSalary()? ":" "). Фактическое значение остается тем же, что и экземпляр Employee.

Ответ 2

Существует еще одно решение, реализующее StringConverter. Это очень полезно для объектов:

public class Producto {

private String codigo;
private String nombre;

public Producto(String codigo, String nombre) {
    this.codigo = codigo;
    this.nombre = nombre;
}

public String getCodigo() {
    return codigo;
}

public void setCodigo(String codigo) {
    this.codigo = codigo;
}

public String getNombre() {
    return nombre;
}

public void setNombre(String nombre) {
    this.nombre = nombre;
}

}

Реализация конвертера:

public class ProductoConverter extends StringConverter<Producto> {

/** Cache de productos */
private Map<String, Producto> mapProductos = new HashMap<String, Producto>();

@Override
public String toString(Producto producto) {
    mapProductos.put(producto.getCodigo(), producto);
    return producto.getNombre();
}

@Override
public Producto fromString(String codigo) {
    return mapProductos.get(codigo);
}

}

Код в представлении:

    ComboBox<Producto> cboProductos  = new ComboBox<Producto>;
    cboProductos.setConverter(new ProductoConverter());
    cboProductos.getItems().addAll(serviciosMgr.getListaProductos());

Чтобы получить значение продукта, вы можете вызвать метод getValue():

cboProductos.getValue()

Ответ 3

Я знаю, что этот вопрос устарел, но потому, что я просто потратил часы на бессмысленные копания по этой проблеме, для меня это обязательное разделение. Похоже, что ComboBox с переопределенным методом toString() решает строки обратно к объектам сразу же, даже если в списке есть дубликаты строк. Разрешение должно быть индексированным, а toString() используется только для представления.