javafxjavafx-8

don't receive mouse press event on child node JavaFX


I want draw path between two imageview same as picture

picture.

this path start from one of these imageview by mouse press, continue by mouse press and move event on pane and must be end in another imageview by mouse press.here is the problem after first mouse press didn't recieve any mouse press event on imageviews, the event just recieves on the pane becuase of that draw line didn't stop. what is wrong in my code ?

here's my controller code :

public class DrawLine {
    @FXML
    ImageView imageView1 ;
    @FXML
    ImageView imageView2 ;
    @FXML
    AnchorPane pane ;
    private  Line currentLine ;
    private  String state ;
    private DoubleProperty mouseX = new SimpleDoubleProperty();
    private DoubleProperty mouseY = new SimpleDoubleProperty();

    @FXML
    private  void initialize(){
        state = "dfkl" ;
        imageView1.setPreserveRatio( false);
        imageView2.setPreserveRatio( false);
        imageView1.setOnMousePressed( event -> {
            imageMousePress( event);
        });
        imageView2.setOnMousePressed( event -> {
            imageMousePress( event);
        });
        pane.setOnMousePressed( event ->  {
            paneMousePress( event) ;
        });
        imageView2.setPickOnBounds(false);
        imageView1.setPickOnBounds(false);
        pane.setOnMouseMoved( event -> {
            paneMouseMove( event);
        });

    }


    public  void paneMouseMove( MouseEvent e) {
        if( this.state.equals("DRAWLINE") && this.currentLine != null) {
            makeLine( e);
        }
    }
    public void paneMousePress( MouseEvent e) {
        if( this.state.equals("DRAWLINE") && this.currentLine != null) {
            endLine(e);
            startLine(e);
        }
    }
    private  void  startLine( MouseEvent e ){
        currentLine = new Line();
        currentLine.setStyle( "-fx-stroke: #a86a6a ; -fx-stroke-width: 5");
        currentLine.setStartX( e.getSceneX());
        currentLine.setStartY(e.getSceneY());
        mouseX.set( e.getSceneX()) ;
        mouseY.set( e.getSceneY());
        currentLine.endXProperty().bind(mouseX);
        currentLine.endYProperty().bind(mouseY);
        pane.getChildren().add(currentLine);
    }
    private  void  endLine (  MouseEvent e){
        currentLine.endXProperty().unbind();
        currentLine.endYProperty().unbind();
        currentLine.setEndX(e.getX());
        currentLine.setEndY(e.getY());
        currentLine = null;
    }
    private  void makeLine( MouseEvent e){
        mouseX.set(e.getX());
        mouseY.set(e.getY());
    }

    private void imageMousePress( MouseEvent event){
        if( currentLine == null){
            startLine(event);
            state = "DRAWLINE" ;
        }else if( currentLine != null & state.equals("DRAWLINE")){
            endLine( event);
        }
    }
}

help me please.


Solution

  • When dragging the end point of the line around, the end is positioned below the mouse cursor. This way the target of the mouse event is the Line, not the ImageView and since there is no event handler for the event for the Line that consumes it, the event is delivered to the parent of the Line which is the AnchorPane, not the ImageView.

    To fix this set the mouseTransparent property of the Line to true:

    private void startLine(MouseEvent e) {
        currentLine = new Line();
        currentLine.setMouseTransparent(true);
        ...
    }
    

    Also you should consume the events for the ImageViews to not trigger the event handler for the AnchorPane too:

    imageView1.setOnMousePressed(event -> {
        imageMousePress(event);
        event.consume();
    });
    imageView2.setOnMousePressed(event -> {
        imageMousePress(event);
        event.consume();
    });
    

    Also note that x and y properties of the MouseEvent are relative to the coordinate system of the Node where the handler is added.

    private void endLine(MouseEvent e) {
        currentLine.endXProperty().unbind();
        currentLine.endYProperty().unbind();
        currentLine.setEndX(e.getX());
        currentLine.setEndY(e.getY());
        currentLine = null;
    }
    

    needs to be changed to

    private void endLine(MouseEvent e) {
        currentLine.endXProperty().unbind();
        currentLine.endYProperty().unbind();
        currentLine = null;
    }
    

    Furthermore if there are a limited number of states, I recommend using a enum instead since this way you get compile time checks for typos. Using strings for this purpose you could accidentally add bugs, e.g. if you accidentally use "DRAWLlNE" instead of "DRAWLINE" which can be hard to spot. Additionally enum constants can be compared using ==.

    private enum States {
        DRAWLINE
    }