I have my JavaFX 2.0 application, where i need to make some action, after user clicked an item in ListView element. To construct user GUI i\'m using FXML, in which i have so
You can also consume unwanted events on blank space.
in call()
of cell factory add:
cell.setOnMousePressed((MouseEvent event) -> {
if (cell.isEmpty()) {
event.consume();
}
});
This will disable click
& dragStart
too.
Whole cellFactory example from my project:
public static Callback<ListView<BlockFactory>, ListCell<BlockFactory>> getCellFactory() {
return new Callback<ListView<BlockFactory>, ListCell<BlockFactory>>() {
@Override
public ListCell<BlockFactory> call(ListView<BlockFactory> param) {
ListCell<BlockFactory> cell = new ListCell<BlockFactory>() {
@Override
protected void updateItem(BlockFactory item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
ImageView img = new ImageView(item.img);
Label label = new Label(item.desc);
HBox bar = new HBox(img, label);
bar.setSpacing(15);
bar.setAlignment(Pos.CENTER_LEFT);
setGraphic(bar);
}
}
};
cell.setOnMousePressed((MouseEvent event) -> {
if (cell.isEmpty()) {
event.consume();
}
});
return cell;
}
};
}
A simple fix to Sergey's answer, without having to create a whole new listCell (in your case you do, but we don't have to in a regular text case).
all you need to simply do is create a temp variable that is equal to the first list item at first, and that gets changed to each new clicked item. Once you try to click the item again, the temp variable knows it's the same, and with an if statement you can get around that.
temp Item is a global that you put up top String tempItem = "admin";
for me I knew my first field is always going to be labeled "admin" so I set it as such. you would have to get the first entry and set it outside of the method you are going to use for list selecting.
private void selUser() throws IOException
{
String item = userList.getSelectionModel().getSelectedItem().toString();
if(item != tempItem)
{
//click, do something
}
tempItem = item;
}
As for me I used an FXML document that called my method
@FXML
public void userSel(MouseEvent mouse) throws IOException
{
selUser();
}
In this case you could just take the entire contents of the selUser() method and put it into the userSel mouse click.
FXML attributes and values are directly mapped to FX API. So to find out how to write handler you can first create required entities by API.
It seems you want to add action on ListView element on mouse click, so you need to add mouse click handler. In API it looks next way:
final ListView lv = new ListView(FXCollections.observableList(Arrays.asList("one", "2", "3")));
lv.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
System.out.println("clicked on " + lv.getSelectionModel().getSelectedItem());
}
});
Looking at that code you can find out what in FXML you need to overrided attribute onMouseClicked
:
<ListView fx:id="listView" onMouseClicked="#handleMouseClick"/>
And in controller you need to provide handler with MouseEvent
parameter:
@FXML
private ListView listView;
@FXML public void handleMouseClick(MouseEvent arg0) {
System.out.println("clicked on " + listView.getSelectionModel().getSelectedItem());
}
answer from @Sergey Grinev may have an issue. if your ListView is filled not enough full, in other words may have some blank space. then you cliked blank space will not tigger selection changing.
the solution: Use custom ListCell.
If you don't know how many items you have. you will not ever only do so. you should use time for space.
Demostrate:
in the ListView code segment:
listView.setCellFactory(new AppListCellFactory());
AppListCellFactory.java:
public class AppListCellFactory implements Callback, ListCell> {
// only one global event handler
private EventHandler<MouseEvent> oneClickHandler;
public AppListCellFactory(){
oneClickHandler = new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
Parent p = (Parent) event.getSource();
// do what you want to do with data.
AppClickHandler.onAppBeanClicked((AppBean) p.getUserData());
}
};
}
@Override
public ListCell<AppBean> call(ListView<AppBean> param) {
return new DemoListCell(oneClickHandler);
}
public static final class DemoListCell extends ListCell<AppBean> {
private EventHandler<MouseEvent> clickHandler;
/**
* This is ListView item root node.
*/
private Parent itemRoot;
private Label label_AppName;
private ImageView imgv_AppIcon;
DemoListCell(EventHandler<MouseEvent> clickHandler) {
this.clickHandler = clickHandler;
}
@Override
protected void updateItem(AppBean app, boolean empty) {
super.updateItem(app, empty);
if (app == null) {
setText(null);
setGraphic(null);
return;
}
if (null == itemRoot) {
try {
itemRoot = FXMLLoader.load(getClass().getResource(("fxml/appList_item.fxml")));
} catch (IOException e) {
throw new RuntimeException(e);
}
label_AppName = (Label) itemRoot.lookup("#item_Label_AppName");
imgv_AppIcon = (ImageView) itemRoot.lookup("#item_ImageView_AppIcon");
itemRoot.setOnMouseClicked(clickHandler);
}
// set user data. like android's setTag(Object).
itemRoot.setUserData(app);
label_AppName.setText(app.name);
imgv_AppIcon.setImage(new Image(getClass().getResource("img/icon_64.png").toExternalForm()));
setGraphic(itemRoot);
}
}
}