Reputation:
I'm learning JavaFX ListView
I want to know why the listViewRight
's items update automatically when I select the listViewLeft
's Item?
FXML Code:
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.ListView ?>
<?import javafx.scene.control.Label ?>
<?import javafx.scene.control.SelectionMode ?>
<?import javafx.scene.control.MultipleSelectionModel ?>
<?import javafx.scene.control.CheckBox ?>
<?import javafx.collections.FXCollections ?>
<?import java.lang.String ?>
<BorderPane prefWidth="600" prefHeight="250" xmlns:fx="http://javafx.com/fxml" fx:controller="ListViewController">
<left>
<ListView fx:id="listViewLeft" editable="true">
<items>
<FXCollections fx:id="collection" fx:factory="observableArrayList">
<String fx:value="Good" />
<String fx:value="Bad" />
<String fx:value="Average" />
</FXCollections>
</items>
</ListView>
</left>
<right>
<ListView fx:id="listViewRight" />
</right>
</BorderPane>
Controller Code:
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
import javafx.scene.control.CheckBox;
import javafx.scene.control.SelectionMode;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.beans.value.ObservableValue;
import javafx.beans.value.ChangeListener;
public class ListViewController{
@FXML private ListView<String> listViewLeft;
@FXML private ObservableList<String> collections;
@FXML private CheckBox newItem;
@FXML private ListView<String> listViewRight;
public void initialize(){
collections = listViewLeft.getItems();
listViewLeft.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
listViewRight.setItems(listViewLeft.getSelectionModel().getSelectedItems());
}
}
When I select item from listViewLeft
then that Item automatically show into the listViewRight
why? I just called listViewLeft.getSelectionModel().getSelectedItems()
to add all selected items to the listViewRight
why it binds
to the listViewRight
?
Upvotes: 1
Views: 1697
Reputation: 209418
A ListView
has a reference to an ObservableList
, which you can access via getItems()
; that ObservableList
contains the elements which are displayed in the list view. The ObservableList
is sometimes referred to as the ListView
's "backing list" (which I'll do here).
The ListView
registers listeners with the backing list, so that if the contents of the list change, the list view is updated.
ListView
(two different ways)There are two ways to change the items displayed by a ListView
. You can either change the contents of the backing list. For example:
listView.getItems().setAll(someCollection);
will remove all the items currently in the backing list, and replace them with all the items in the supplied collection.
Alternatively, you can provide a new backing list entirely:
listView.setItems(someObservableList);
This will tell the ListView
to use someObservableList
as its backing list. It will remove any listeners it had registered with the current backing list, add listeners to the list you provide, and the contents of the list you provide will become the contents of the list view.
ListView
The selection model exposes an ObservableList
containing the selected items in the list, via listView.getSelectionModel().getSelectedItems()
. The ListView
updates this list automatically when the user selects or deselects items in the list view. Since this is an ObservableList
, you can register listeners with it in order to be notified when its contents change, i.e. when items are selected or deselected.
So in the code you provided you do:
listViewRight.setItems(listViewLeft.getSelectionModel().getSelectedItems());
This tells listViewRight
to use the list of selected items from listViewLeft
as its backing list. I.e. if the contents of listViewLeft.getSelectionModel().getSelectedItems()
change, then the contents of the ListView
change: that's the purpose of a backing list.
On the other hand, if you had instead done
listViewRight.getItems().setAll(listViewLeft.getSelectionModel().getSelectedItems());
you would have replaced the content of listViewRight
's current backing list with the selected items in listViewLeft
(i.e. you would clear the backing list and copy the selected items in listViewLeft
to the backing list). In this case subsequent changes to listViewLeft.getSelectionModel().getSelectedItems()
would not be reflected in the backing list of listViewRight
.
Upvotes: 1
Reputation: 619
You should have a read in the ListView JavaFX 8 Documentation from (https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/ListView.html). For your problem have a look at the following part:
Populating a ListView
A simple example of how to create and populate a ListView of names (Strings) is shown here:
ObservableList<String> names = FXCollections.observableArrayList("Julia", "Ian", "Sue", "Matthew", "Hannah", "Stephan", "Denise");
ListView<String> listView = new ListView<String>(names);
The elements of the ListView are contained within the items ObservableList. This ObservableList is automatically observed by the ListView, such that any changes that occur inside the ObservableList will be automatically shown in the ListView itself. If passying the ObservableList in to the ListView constructor is not feasible, the recommended approach for setting the items is to simply call:
ObservableList<T> content = ...
listView.setItems(content);
The end result of this is, as noted above, that the ListView will automatically refresh the view to represent the items in the list. Another approach, whilst accepted by the ListView, is not the recommended approach:
List<T> content = ...
getItems().setAll(content);
So what you're trying to to is the not the recommended approach. For you to test, change your code
listViewRight.setItems(listViewLeft.getSelectionModel().getSelectedItems());
to
listViewRight.getItems().setAll(listViewLeft.getSelectionModel().getSelectedItems());
Upvotes: 1