Est-il possible de définir cell Factory deux fois pour Listview dans Javafx
J'ai défini une usine de cellules dans la vue Liste pour changer la couleur de la cellule sélectionnée.Et un autre est pour l'action glisser-déposer.Les deux ne fonctionnent pas en même temps. Usine de cellules: 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 answers
setCellFactory
est une méthode de jeu, et il se comporte comme n'importe quelle autre méthode: soit, il définit la valeur de la ListView
's (seul et unique) cellFactory
la propriété. Tout comme si vous aviez du code comme
someObject.setIntValue(5);
someObject.setIntValue(42);
Que Vous attendez someObject
's intValue
propriété 42
, si vous appelez setCellFactory
deux fois, la cellule de l'usine sera la deuxième valeur que vous lui transmettez.
L'approche la plus simple de ce que vous dites que vous essayez de faire est de simplement combiner toutes les fonctionnalités dans une seule usine de cellules:
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 ;
});
Si vous vous voulez vraiment séparer les choses en différentes implémentations d'usine, vous pouvez utiliser une approche de type "décorateur":
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);
}
};
}
}
Ajouter la couleur:
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 ;
}
}
Et glisser-déposer:
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 ;
}
}
Et maintenant vous pouvez faire
PlainCellFactory plainFactory = new PlainCellFactory();
ColorListCellFactory colorFactory = new ColorListCellFactory(plainFactory);
DragAndDropListCellFactory dndFactory = new DragAndDropListCellFactory(colorFactory);
listView.setCellFactory(dndFactory);
Est-il possible de définir cell factory deux fois pour
ListView
dans JavaFX?
Il est possible de remplacer la fabrique de cellules, mais vous ne pouvez pas faire en sorte que ListView
utilise plus d'une fabrique pour créer une cellule.
Cependant, vous pouvez utiliser une usine de cellules qui gère l'initialisation/remplacement de l'élément en invoquant du code à partir d'autres objets (modèle de stratégie). Cela vous permet d'utiliser combiner différents comportements sans avoir besoin de réimplémenter la cellule.
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);
}
}
Exemple utiliser
@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();
}