3

I have a javafx application which contains a listview with a custom cell factory. each cell contains a button to do a specific action for that cell. before updating to java 8 every thing was ok but after running my app with java 8 when i click the button instead of handling event by button, the whole cell is selected. Here is my code:

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;

public class CustomCell extends ListCell<String> {
    private Button actionBtn;   

    public CustomCell() {
        super();    

        setOnMouseClicked(new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent event) {              
                //do something                  
            }
        });     
    }

    @Override
    public void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        setEditable(false);
        if (item != null) {
            Label name = new Label(item);                           
            actionBtn = new Button("my action");            
            actionBtn.setOnAction(new EventHandler<ActionEvent>() {

                @Override
                public void handle(ActionEvent arg0) {
                    System.out.println("hiiiiiiiii");

                }
            });                     

            GridPane pane = new GridPane();
            pane.getStyleClass().add("gridpane");           
            pane.add(name, 0, 0);
            pane.add(actionBtn, 0, 1);              
            setGraphic(pane);
        } else {
            setText(null);
            setGraphic(null);
        }
    }   
}
user3545782
  • 33
  • 1
  • 4

1 Answers1

5

That's a bug, which has been filed. See this discussion on OTN.

As in that discussion, I would strongly recommend not creating new controls in the updateItem(...) method. It's much better to create them once for the cell, and then to configure them in updateItem(...). For example:

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;

public class CustomCell extends ListCell<String> {
    private Button actionBtn;   
    private Label name ;
    private GridPane pane ;

    public CustomCell() {
        super();    

        setOnMouseClicked(new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent event) {              
                //do something                  
            }
        }); 

        actionBtn = new Button("my action");
        actionBtn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                System.out.println("Action: "+getItem());
            }
        });
        name = new Label();
        pane = new GridPane();
        pane.add(name, 0, 0);
        pane.add(actionBtn, 0, 1);
        setText(null);
    }

    @Override
    public void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        setEditable(false);
        if (item != null) {
            name.setText(item);                          
            setGraphic(pane);
        } else {
            setGraphic(null);
        }
    }   
}

As well as being considerably more efficient, this also provides a workaround for the bug.

James_D
  • 201,275
  • 16
  • 291
  • 322
  • @James_D What about have only one shared action handler (static?) between `button`s? I assume that the logic in such handler is still same for the whole `ListView`, only works with the concrete item. Do you agree/disagree? – David Apr 24 '17 at 17:20
  • @David I don't like that approach at all. The action handler almost always needs to access the item in the list, which it can only do via the cell. So if you have a single handler for all the buttons, you end up with very convoluted code to figure out which button has been pressed. Use a different handler for each control. – James_D Apr 24 '17 at 17:52