I want draw path between two imageview same as 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.
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 ImageView
s 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
}