Reputation: 155
Sorry for bothering with such wide explained topic. I have been creating dialog to pick string values from one list to another. There is list of options at the start. get/setSourceItems and get/setTargetItems are getters and setters for ObservableLists
private ListView<String> sourceListView;
private ObservableList<String> sourceItems;
private ListView<String> targetListView;
private ObservableList<String> targetItems;
List<String> options = getSelectedMetaDataList();
setSourceItems(FXCollections.observableArrayList(options));
sourceListView = new ListView(getSourceItems());
setTargetItems(FXCollections.observableArrayList(new ArrayList()));
targetListView = new ListView(getTargetItems());
Dialog shows listViews well at the start. Source is filled with options and target is empty. But when I use button then nothing happens on UI. For example when I move all items from source to target I can see items in targetItems observableList but nothing in targetListView on UI.
Button selectAllBtn = new Button(">>");
selectAllBtn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
if (getSourceItems().size() > 0) {
setTargetItems(getSourceItems());
targetListView.refresh();
setSourceItems(null);
sourceListView.refresh();
System.out.println("selectAllBtn target: " + getTargetItems().toString());
}
}
});
Something wrong is with selection model too. Because when I try move selected items sourceListView.getSelectionModel().getSelectedItems() is empty even when I have item highlighted. I tried to move items not only by observableList but using targetListView.getItems().addAll(movingItems); Still no changes on UI.
Button selectOneBtn = new Button(">");
selectOneBtn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
ObservableList<String> movingItems = sourceListView.getSelectionModel().getSelectedItems();
System.out.println("selectOneBtn: " + sourceListView.getSelectionModel().getSelectedItems().size());
System.out.println("selectOneBtn: " + targetListView.getSelectionModel().getSelectedItems().size());
if (movingItems.size() > 0) {
System.out.println("selectOneBtn: " + movingItems.toString());
sourceListView.getSelectionModel().clearSelection();
sourceListView.getItems().removeAll(movingItems);
sourceListView.refresh();
targetListView.getItems().addAll(movingItems);
targetListView.refresh();
System.out.println("selectOneBtn source: " + getSourceItems().toString());
System.out.println("selectOneBtn target: " + getTargetItems().toString());
}
}
});
Thanks in advance.
Upvotes: 0
Views: 26564
Reputation: 13859
I am guessing you are trying to do something similar to this.
@FXML ListView lv1, lv2;
ArrayList options = new ArrayList();
ObservableList<String> items;
ObservableList<String> items2;
//This is used to get the selected item from lv1 and add it to lv2
@FXML
private void handleButtonAction(ActionEvent event) {
items2.add(lv1.getSelectionModel().getSelectedItem().toString());
}
//This is used to get all items from lv1 and add them to lv2
@FXML
private void handleGetAllButtonAction(ActionEvent event)
{
for(String entry : items)
{
items2.add(entry);
}
}
@Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
options.add("hello");
options.add("bye");
options.add("hola");
items = FXCollections.observableArrayList(options);
items2 = FXCollections.observableArrayList();
System.out.println(items.size());
lv1.setItems(items);
lv2.setItems(items2);
}
Upvotes: 0
Reputation: 209418
You change the underlying observable list, but you never tell the list view to use the new list:
Button selectAllBtn = new Button(">>");
selectAllBtn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
if (getSourceItems().size() > 0) {
setTargetItems(getSourceItems());
targetListView.setItems(getTargetItems());
// use an empty list, not null:
setSourceItems(FXCollections.observableArrayList());
sourceListView.setItems(getSourceItems());
System.out.println("selectAllBtn target: " + getTargetItems().toString());
}
}
});
Alternatively, instead of changing to a new list, just change the contents of the existing list. Since the lists are observable, the listviews will see the changes automatically:
Button selectAllBtn = new Button(">>");
selectAllBtn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
if (getSourceItems().size() > 0) {
getTargetItems().setAll(getSourceItems());
getSourceItems().clear();
System.out.println("selectAllBtn target: " + getTargetItems().toString());
}
}
});
For your selection problem, you get a reference to the list of selected items:
ObservableList<String> movingItems = sourceListView.getSelectionModel().getSelectedItems();
and then you clear the selection:
sourceListView.getSelectionModel().clearSelection();
which will, of course, make the list of selected items empty.
So now when you do
sourceListView.getItems().removeAll(movingItems);
targetListView.getItems().addAll(movingItems);
you are passing in an empty list each time, and so nothing will change.
Instead, copy the selected items:
List<String> movingItems = new ArrayList<>(sourceListView.getSelectionModel().getSelectedItems());
and then
sourceListView.getItems().removeAll(movingItems);
targetListView.getItems().addAll(movingItems);
will have the desired effect (no need to call refresh()
).
Here is a SSCCE (note I unified both behaviors into a single method, since they are essentially the same):
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class MoveItemsBetweenListViews extends Application {
private ObservableList<String> sourceItems;
private ObservableList<String> targetItems;
@Override
public void start(Stage primaryStage) {
sourceItems = FXCollections.observableArrayList("One", "Two", "Three", "Four");
targetItems = FXCollections.observableArrayList();
ListView<String> sourceListView = new ListView<>(sourceItems);
ListView<String> targetListView = new ListView<>(targetItems);
Button moveAllButton = new Button(">>");
Button moveSelectedButton = new Button(">");
moveAllButton.setOnAction(e -> moveItems(sourceItems));
moveSelectedButton.setOnAction(e -> moveItems(sourceListView.getSelectionModel().getSelectedItems()));
VBox buttons = new VBox(10, moveAllButton, moveSelectedButton);
buttons.setAlignment(Pos.CENTER);
BorderPane root = new BorderPane(buttons, null, targetListView, null, sourceListView);
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private void moveItems(List<String> itemsToMove) {
List<String> movingItems = new ArrayList<>(itemsToMove);
sourceItems.removeAll(movingItems);
targetItems.addAll(movingItems);
}
public static void main(String[] args) {
launch(args);
}
}
Upvotes: 3