How to add a mouse doubleclick event listener to the cells of a ListView in javafx?
Asked Answered
S

3

19

I have a list of links in a ListView. I want to add an mouseEventListener to each cell of the list so that whenever a user double clicks the list item link is opened. I can write the functionality of opening the link on my own but I am not able to add the doubleclick event with every cell in the list. Please help...

Streamliner answered 20/3, 2014 at 18:29 Comment(0)
B
38

Let us consider your ListView as playList. Now you can implement the mouse listener with double click functionality on each cell using

playList.setOnMouseClicked(new EventHandler<MouseEvent>() {

    @Override
    public void handle(MouseEvent click) {

        if (click.getClickCount() == 2) {
           //Use ListView's getSelected Item
           currentItemSelected = playList.getSelectionModel()
                                                    .getSelectedItem();
           //use this to do whatever you want to. Open Link etc.
        }
    }
});
Benito answered 21/3, 2014 at 2:53 Comment(4)
Approach works, but does also fire as soon as you click twice in a "empty" space in the listview. Can you somehow bind that only on the items?Tabaret
@Lucè Brùlè its depend on where you attach the event.Toro
I think it needs a ); after the last } at the bottom.Hexane
@Hexane Good catch! ;)Benito
H
12

I had to solve the same sort of issue, my ListView contains a grid pane and labeled text so you'll have to change the 'instanceof' and the other side of the 'or' to what you have.

(Assuming your ListView is named listView):

listView.setOnMouseClicked(new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent event) {
        if(event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 2 &&
           (event.getTarget() instanceof LabeledText || ((GridPane) event.getTarget()).getChildren().size() > 0)) {

           //your code here        
         }    
    }
});

It is possible if the user clicks near the very edge of the item and the border of the ListView for it not to pass the if loop but it sounds like the user won't be doing that in your case.

Hope this helps.

Huff answered 23/11, 2016 at 16:11 Comment(0)
A
0

Answer might be lengthy as I am trying to provide exactly what user asked. I am considering usage of fxml, but the answer is applicable if one is not using fxml. I am also using a custom CellFactory to render individual list items.

This answer follows MVC pattern. Also, I have skipped all import statements in the code.

So, we need these files. Name of each file is self-explanatory.

  • ItemModel.java
  • PrimaryScene.fxml
  • PrimarySceneController.java
  • ListItem.fxml
  • ListItemController.java
  • ListItemCellFactory.java
  • ListItemCell.java
  • OnItemDoubleClickListener.java

ItemModel.java

public class ItemModel{
    private String name;
    private String description;
    
    // All Getters, and Setters here ....
}

OnItemDoubleClickListener.java

public interface OnItemDoubleClickListener{
    public void handleDoubleClick(MouseEvent event, ItemModel model);
}

PrimaryScene.fxml

<AnchorPane xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="PrimarySceneController">
   <ListView fx:id="listView" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</AnchorPane>

PrimarySceneController.java

public class PrimarySceneController implements Initializable, OnItemDoubleClickListener{
    
    @FXML
    public ListView<ItemModel> listView;

    private final ObservableList<ItemModel> items = FXCollections.observableArrayList();

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        listView.setCellFactory(new ListItemCellFactory(this));
        listView.setItems(items);

        // TODO: populate items here ...
    }

    @Override
    public void handleDoubleClick(MouseEvent event, ItemModel model){
        // TODO: Item was double clicked. Do your thing.
    }
}

ListItem.fxml

<AnchorPane xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:id="root">
   <VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
      <Label fx:id="labelName" text="Label"/>
      <Label fx:id="labelDescription" text="Label/>
   </VBox>
</AnchorPane>

ListItemController.java

private static class ListItemController implements Initializable{
    @FXML
    private AnchorPane root;

    @FXML
    private Label labelName;

    @FXML
    private Label labelDescription;
    
    private final OnItemDoubleClickListener listener;

    public ListItemController(OnItemDoubleClickListener listener){
        this.listener = listener;
    }

    public void draw(ItemModel model) {
        labelName.setText(model.getName());
        labelDescription.setText(model.getDescription());
        
        // Magic happens here
        root.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                if(event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 2){
                    this.listener.handleDoubleClick(event, model);
                }                    
            }
        });
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {

    }
}

ListItemCellFactory.java

public class ListItemCellFactory implements Callback<ListView<ItemModel>, ListCell<ItemModel>> {
    
    
    private final OnItemDoubleClickListener listener;

    public ListItemCellFactory(OnItemDoubleClickListener listener){
        this.listener = listener;
    }

    @Override
    public ListCell<ItemModel> call(ListView<ItemModel> listView) {
        FXMLLoader fxmlLoader = new FXMLLoader();
        ListItemController controller = new ListItemController(this.listener);
        fxmlLoader.setController(controller);
        Node graphic = fxmlLoader.load(getClass().getResourceAsStream("/ListItem.fxml"));
        return new ListItemCell(graphic, controller);
    }
}

The code above assumes that /ListItem.fxml is inside resources directory.

ListItemCell.java

private static class ListItemCell extends ListCell<ItemModel> {

    private final Node graphic;
    private final ListItemController controller;

    public ListItemCell(Node graphic, ListItemController controller) {
        this.graphic = graphic;
        this.controller = controller;
    }

    @Override
    protected void updateItem(ItemModel item, boolean empty) {
        super.updateItem(item, empty);
        if (empty){
            setText(null);
            setGraphic(null);
            return;
        }

        setText(null);
        setGraphic(graphic);
        controller.draw(item);
    }
}
Allomorphism answered 2/11, 2023 at 14:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.