是否可以在Javafx中为Listview设置两次单元格工厂

时间:2016-11-23 07:51:16

标签: javafx

我在列表视图中设置了一个单元格工厂来更改所选单元格的颜色。另一个单元格用于拖放操作。它们不能同时工作。 细胞工厂:1

listView.setCellFactory( new Callback<ListView<String>, ListCell<String>>()
        {
            @Override
            public ListCell<String> call( ListView<String> param )
            {
                ListCell<String> listCell = new ListCell<String>()
                {
                    @Override
                    protected void updateItem( String item, boolean empty )
                    {
                        super.updateItem( item, empty );
                        setText( item );
                    }
                };
Cell factory:2
listView.setCellFactory(list -> {

                    ListCell<String> cell = new ListCell<String>() {
                        @Override
                        protected void updateItem(String item, boolean empty) {
                            super.updateItem(item, empty);
                            setText(empty ? null : item);

                        }
                    };

2 个答案:

答案 0 :(得分:3)

setCellFactory是一个set方法,它的行为与任何其他set方法类似:即它设置ListView(一个且唯一的)cellFactory属性的值。就像你有像

这样的代码
someObject.setIntValue(5);
someObject.setIntValue(42);

您希望someObject intValue属性为42,如果您拨打setCellFactory两次,则单元格工厂将成为您传递的第二个值它。

您所说的最简单的方法是简单地将单个单元工厂中的所有功能组合在一起:

listView.setCellFactory(list -> {

    ListCell<String> cell = new ListCell<String>() {
        @Override
        protected void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            setText(empty ? "" : item);

            // modify color here depending on item...
        }
    };

    cell.setOnDragDetected(e -> { /* ... */ });
    // other drag handlers...

    return cell ;
});

如果你真的想把东西分成不同的工厂实现,你可以使用&#34;装饰器&#34;类型方法:

public class PlainCellFactory implements Callback<ListView<String, ListCell<String>> {
    @Override
    public ListCell<String> call(ListView<String> list) {
        return new ListCell<String>() {
            @Override
            protected void updateItem(String item, boolean empty) {
                super.updateItem(item, empty) ;
                setText(empty ? "" : item);
            }
        };
    }
}

添加颜色:

public class ColorListCellFactory implements Callback<ListView<String>, ListCell<String>> {

    private final Callback<ListView<String>, ListCell<String>> originalFactory ;

    public ColorListCellFactory(Callback<ListView<String>, ListCell<String>> originalFactory) {
        this.originalFactory = originalFactory ;
    }

    @Override
    public ListCell<String> call(ListView<String> list) {
        ListCell<String> cell = originalFactory.call(list);
        cell.itemProperty().addListener((obs, oldItem, newItem) -> {
            // change color depending on newItem (which might be null)...
        });
        return cell ;
    }
}

并拖放:

public class DragAndDropListCellFactory implements Callback<ListView<String>, ListCell<String>> {

    private final Callback<ListView<String>, ListCell<String>> originalFactory ;

    public DragAndDropListCellFactory(Callback<ListView<String>, ListCell<String>> originalFactory) {
        this.originalFactory = originalFactory ;
    }

    @Override
    public ListCell<String> call(ListView<String> list) {
        ListCell<String> cell = originalFactory.call(list);
        cell.setOnDragDetected(e -> { /* ... */ });
        // other drag handlers...
        return cell ;
    }
}

现在你可以做到

PlainCellFactory plainFactory = new PlainCellFactory();
ColorListCellFactory colorFactory = new ColorListCellFactory(plainFactory);
DragAndDropListCellFactory dndFactory = new DragAndDropListCellFactory(colorFactory);
listView.setCellFactory(dndFactory);

答案 1 :(得分:1)

  

是否可以在JavaFX中为ListView设置两次单元格工厂?

可以更换单元工厂,但不能让ListView使用多个工厂来创建单元格。

但是,您可以使用通过调用其他对象(策略模式)的代码来处理项目初始化/替换的单元工厂。这允许您使用组合不同的行为,而无需重新实现单元格。

public class MultiBehaviorListCell<S> extends ListCell<S> {

    public static interface Behavior<T> {

        default void initialize(MultiBehaviorListCell<T> cell) {
        }

        void updateItem(MultiBehaviorListCell<T> cell, T item, boolean empty);
    }

    public static <T> Callback<ListView<T>, ListCell<T>> factory(final Behavior<T>... behaviors) {
        Objects.requireNonNull(behaviors);
        return factory(Arrays.asList(behaviors));
    }

    private final Iterable<Behavior<S>> behaviors;

    private MultiBehaviorListCell(Iterable<Behavior<S>> behaviors) {
        this.behaviors = behaviors;

        // let behaviors handle initialisation
        for (Behavior b : behaviors) {
            try {
                b.initialize(this);
            } catch (RuntimeException ex) {
            }
        }
    }

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

        // let behaviors handle item replacement
        for (Behavior<S> b : behaviors) {
            try {
                b.updateItem(this, item, empty);
            } catch (RuntimeException ex) {
            }
        }
    }

    public static <T> Callback<ListView<T>, ListCell<T>> factory(final Iterable<Behavior<T>> behaviors) {
        Objects.requireNonNull(behaviors);
        return l -> new MultiBehaviorListCell<>(behaviors);
    }

}

使用示例

@Override
public void start(Stage primaryStage) {
    ListView<Integer> listView = new ListView<>();
    listView.getItems().addAll(1, 2, 3, 4);

    EventHandler<MouseEvent> mouseClicked = evt -> {
        MultiBehaviorListCell<Integer> source = (MultiBehaviorListCell<Integer>) evt.getSource();
        System.out.println(source.getItem());
    };

    listView.setCellFactory(MultiBehaviorListCell.factory(
            // setting text
            (cell, number, empty) -> cell.setText(empty || number == null ? "" : number.toString()),

            // changing background / text color
            new MultiBehaviorListCell.Behavior<Integer>() {

                @Override
                public void updateItem(MultiBehaviorListCell<Integer> cell, Integer item, boolean empty) {
                }

                @Override
                public void initialize(MultiBehaviorListCell<Integer> cell) {
                    cell.setBackground(new Background(new BackgroundFill(Color.YELLOW, CornerRadii.EMPTY, Insets.EMPTY)));
                    cell.setTextFill(Color.BLACK);
                }

            },

            // registering handler for non-empty cells
            (cell, number, empty) -> cell.setOnMouseClicked(empty ? null : mouseClicked)
    ));

    Scene scene = new Scene(listView);

    primaryStage.setScene(scene);
    primaryStage.show();
}