Hallo zusammen,
ich habe Probleme mit der Maussteuerung. Bei mir wird die Maus nur auf dem letzten Pane (F) angezeigt. Die andere Panes, die gleiche Circles beinhalten, werden ignoriert, als ob sie gar nicht existieren. Kann jemand den Code unten ausführen und schauen, ob das Problem nur bei mir ist.
VG
ich habe Probleme mit der Maussteuerung. Bei mir wird die Maus nur auf dem letzten Pane (F) angezeigt. Die andere Panes, die gleiche Circles beinhalten, werden ignoriert, als ob sie gar nicht existieren. Kann jemand den Code unten ausführen und schauen, ob das Problem nur bei mir ist.
VG
Java:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.value.ChangeListener;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
public class ConnectCircle extends Application {
double sceneX, sceneY, layoutX, layoutY;
private int fieldWidth;
private int fieldHeight;
private double radius;
@Override
public void start(Stage stage) throws Exception {
StackPane root = new StackPane();
root.setPadding(new Insets(20));
Pane pane1 = connectedCircles(800, 600, "A", 30.0, 100.0, 200.0, 100.0, 300.0);
Pane pane2 = connectedCircles(800, 600, "B", 30.0, 200.0, 200.0, 200.0, 300.0);
Pane pane3 = connectedCircles(800, 600, "C", 30.0, 300.0, 200.0, 300.0, 300.0);
Pane pane4 = connectedCircles(800, 600, "D", 30.0, 400.0, 200.0, 400.0, 300.0);
Pane pane5 = connectedCircles(800, 600, "E", 30.0, 500.0, 200.0, 500.0, 300.0);
Pane pane6 = connectedCircles(800, 600, "F", 30.0, 600.0, 200.0, 600.0, 300.0);
root.getChildren().addAll(pane1, pane2, pane3, pane4, pane5, pane6);
Scene sc = new Scene(root, 800, 600);
stage.setScene(sc);
stage.show();
}
Pane connectedCircles(int fieldWidth, int fieldHeight, String text, double radius, double startPosX,
double startPosY, double targetPosX, double targetPosY) {
this.fieldWidth = fieldWidth;
this.fieldHeight = fieldHeight;
this.radius = radius;
Pane pane = new Pane();
StackPane dotA = getDot(Color.BROWN, text, "start", radius, startPosX, startPosY);
StackPane dotB = getDot(Color.GRAY, text, "finish", radius, targetPosX, targetPosY);
buildSingleDirectionalLine(dotA, dotB, pane, true, false); // A --> B
// buildSingleDirectionalLine(dotB, dotC, pane, true, true); // B <--> C
// buildSingleDirectionalLine(dotC, dotD, pane, true, false); // C --> D
// D <===> E
// buildBiDirectionalLine(true, dotD, dotE, pane);
// buildBiDirectionalLine(false, dotD, dotE, pane);
// pane.getChildren().addAll(dotA, dotB, dotC, dotD, dotE);
pane.getChildren().addAll(dotA, dotB);
return pane;
}
/**
* Builds the single directional line with pointing arrows at each end.
*
* @param startDot Pane for considering start point
* @param endDot Pane for considering end point
* @param parent Parent container
* @param hasEndArrow Specifies whether to show arrow towards end
* @param hasStartArrow Specifies whether to show arrow towards start
*/
private void buildSingleDirectionalLine(StackPane startDot, StackPane endDot, Pane parent, boolean hasEndArrow,
boolean hasStartArrow) {
Line line = getLine(startDot, endDot);
StackPane arrowAB = getArrow(true, line, startDot, endDot);
if (!hasEndArrow) {
arrowAB.setOpacity(0);
}
StackPane arrowBA = getArrow(false, line, startDot, endDot);
if (!hasStartArrow) {
arrowBA.setOpacity(0);
}
StackPane weightAB = getWeight(line);
//parent.getChildren().addAll(line, weightAB, arrowBA, arrowAB);
parent.getChildren().addAll(line, arrowBA, arrowAB);
}
/**
* Builds the bi directional line with pointing arrow at specified end.
*
* @param isEnd Specifies whether the line is towards end or not. If false
* then the line is towards start.
* @param startDot Pane for considering start point
* @param endDot Pane for considering end point
* @param parent Parent container
*/
private void buildBiDirectionalLine(boolean isEnd, StackPane startDot, StackPane endDot, Pane parent) {
Line virtualCenterLine = getLine(startDot, endDot);
virtualCenterLine.setOpacity(0);
StackPane centerLineArrowAB = getArrow(true, virtualCenterLine, startDot, endDot);
centerLineArrowAB.setOpacity(0);
StackPane centerLineArrowBA = getArrow(false, virtualCenterLine, startDot, endDot);
centerLineArrowBA.setOpacity(0);
Line directedLine = new Line();
directedLine.setStroke(Color.RED);
directedLine.setStrokeWidth(2);
double diff = isEnd ? -centerLineArrowAB.getPrefWidth() / 2 : centerLineArrowAB.getPrefWidth() / 2;
final ChangeListener<Number> listener = (obs, old, newVal) -> {
Rotate r = new Rotate();
r.setPivotX(virtualCenterLine.getStartX());
r.setPivotY(virtualCenterLine.getStartY());
r.setAngle(centerLineArrowAB.getRotate());
Point2D point = r
.transform(new Point2D(virtualCenterLine.getStartX(), virtualCenterLine.getStartY() + diff));
directedLine.setStartX(point.getX());
directedLine.setStartY(point.getY());
Rotate r2 = new Rotate();
r2.setPivotX(virtualCenterLine.getEndX());
r2.setPivotY(virtualCenterLine.getEndY());
r2.setAngle(centerLineArrowBA.getRotate());
Point2D point2 = r2.transform(new Point2D(virtualCenterLine.getEndX(), virtualCenterLine.getEndY() - diff));
directedLine.setEndX(point2.getX());
directedLine.setEndY(point2.getY());
};
centerLineArrowAB.rotateProperty().addListener(listener);
centerLineArrowBA.rotateProperty().addListener(listener);
virtualCenterLine.startXProperty().addListener(listener);
virtualCenterLine.startYProperty().addListener(listener);
virtualCenterLine.endXProperty().addListener(listener);
virtualCenterLine.endYProperty().addListener(listener);
StackPane mainArrow = getArrow(isEnd, directedLine, startDot, endDot);
parent.getChildren().addAll(virtualCenterLine, centerLineArrowAB, centerLineArrowBA, directedLine, mainArrow);
}
/**
* Builds a line between the provided start and end panes center point.
*
* @param startDot Pane for considering start point
* @param endDot Pane for considering end point
* @return Line joining the layout center points of the provided panes.
*/
private Line getLine(StackPane startDot, StackPane endDot) {
Line line = new Line();
line.setStroke(Color.GRAY);
line.setStrokeWidth(2);
line.startXProperty().bind(
startDot.layoutXProperty().add(startDot.translateXProperty()).add(startDot.widthProperty().divide(2)));
line.startYProperty().bind(
startDot.layoutYProperty().add(startDot.translateYProperty()).add(startDot.heightProperty().divide(2)));
line.endXProperty()
.bind(endDot.layoutXProperty().add(endDot.translateXProperty()).add(endDot.widthProperty().divide(2)));
line.endYProperty()
.bind(endDot.layoutYProperty().add(endDot.translateYProperty()).add(endDot.heightProperty().divide(2)));
return line;
}
/**
* Builds an arrow on the provided line pointing towards the specified pane.
*
* @param toLineEnd Specifies whether the arrow to point towards end pane or
* start pane.
* @param line Line joining the layout center points of the provided panes.
* @param startDot Pane which is considered as start point of line
* @param endDot Pane which is considered as end point of line
* @return Arrow towards the specified pane.
*/
private StackPane getArrow(boolean toLineEnd, Line line, StackPane startDot, StackPane endDot) {
double size = 12; // Arrow size
StackPane arrow = new StackPane();
arrow.setStyle(
"-fx-background-color:#333333;-fx-border-width:1px;-fx-border-color:black;-fx-shape: \"M0,-4L4,0L0,4Z\"");//
arrow.setPrefSize(size, size);
arrow.setMaxSize(size, size);
arrow.setMinSize(size, size);
// Determining the arrow visibility unless there is enough space between dots.
DoubleBinding xDiff = line.endXProperty().subtract(line.startXProperty());
DoubleBinding yDiff = line.endYProperty().subtract(line.startYProperty());
BooleanBinding visible = (xDiff.lessThanOrEqualTo(size).and(xDiff.greaterThanOrEqualTo(-size))
.and(yDiff.greaterThanOrEqualTo(-size)).and(yDiff.lessThanOrEqualTo(size))).not();
arrow.visibleProperty().bind(visible);
// Determining the x point on the line which is at a certain distance.
DoubleBinding tX = Bindings.createDoubleBinding(() -> {
double xDiffSqu = (line.getEndX() - line.getStartX()) * (line.getEndX() - line.getStartX());
double yDiffSqu = (line.getEndY() - line.getStartY()) * (line.getEndY() - line.getStartY());
double lineLength = Math.sqrt(xDiffSqu + yDiffSqu);
double dt;
if (toLineEnd) {
// When determining the point towards end, the required distance is total length
// minus (radius + arrow half width)
dt = lineLength - (endDot.getWidth() / 2) - (arrow.getWidth() / 2);
} else {
// When determining the point towards start, the required distance is just
// (radius + arrow half width)
dt = (startDot.getWidth() / 2) + (arrow.getWidth() / 2);
}
double t = dt / lineLength;
double dx = ((1 - t) * line.getStartX()) + (t * line.getEndX());
return dx;
}, line.startXProperty(), line.endXProperty(), line.startYProperty(), line.endYProperty());
// Determining the y point on the line which is at a certain distance.
DoubleBinding tY = Bindings.createDoubleBinding(() -> {
double xDiffSqu = (line.getEndX() - line.getStartX()) * (line.getEndX() - line.getStartX());
double yDiffSqu = (line.getEndY() - line.getStartY()) * (line.getEndY() - line.getStartY());
double lineLength = Math.sqrt(xDiffSqu + yDiffSqu);
double dt;
if (toLineEnd) {
dt = lineLength - (endDot.getHeight() / 2) - (arrow.getHeight() / 2);
} else {
dt = (startDot.getHeight() / 2) + (arrow.getHeight() / 2);
}
double t = dt / lineLength;
double dy = ((1 - t) * line.getStartY()) + (t * line.getEndY());
return dy;
}, line.startXProperty(), line.endXProperty(), line.startYProperty(), line.endYProperty());
arrow.layoutXProperty().bind(tX.subtract(arrow.widthProperty().divide(2)));
arrow.layoutYProperty().bind(tY.subtract(arrow.heightProperty().divide(2)));
DoubleBinding endArrowAngle = Bindings.createDoubleBinding(() -> {
double stX = toLineEnd ? line.getStartX() : line.getEndX();
double stY = toLineEnd ? line.getStartY() : line.getEndY();
double enX = toLineEnd ? line.getEndX() : line.getStartX();
double enY = toLineEnd ? line.getEndY() : line.getStartY();
double angle = Math.toDegrees(Math.atan2(enY - stY, enX - stX));
if (angle < 0) {
angle += 360;
}
return angle;
}, line.startXProperty(), line.endXProperty(), line.startYProperty(), line.endYProperty());
arrow.rotateProperty().bind(endArrowAngle);
return arrow;
}
/**
* Builds a pane at the center of the provided line.
*
* @param line Line on which the pane need to be set.
* @return Pane located at the center of the provided line.
*/
private StackPane getWeight(Line line) {
double size = radius;
StackPane weight = new StackPane();
weight.setStyle("-fx-background-color:grey;-fx-border-width:1px;-fx-border-color:black;");
weight.setPrefSize(size, size);
weight.setMaxSize(size, size);
weight.setMinSize(size, size);
DoubleBinding wgtSqrHalfWidth = weight.widthProperty().divide(2);
DoubleBinding wgtSqrHalfHeight = weight.heightProperty().divide(2);
DoubleBinding lineXHalfLength = line.endXProperty().subtract(line.startXProperty()).divide(2);
DoubleBinding lineYHalfLength = line.endYProperty().subtract(line.startYProperty()).divide(2);
weight.layoutXProperty().bind(line.startXProperty().add(lineXHalfLength.subtract(wgtSqrHalfWidth)));
weight.layoutYProperty().bind(line.startYProperty().add(lineYHalfLength.subtract(wgtSqrHalfHeight)));
return weight;
}
/**
* Builds a pane consisting of circle with the provided specifications.
*
* @param color Color of the circle
* @param text Text inside the circle
* @return Draggable pane consisting a circle.
*/
private StackPane getDot(Color color, String text, String position, double radius, double startPosX,
double startPosY) {
double paneSize = 2 * radius;
StackPane dotPane = new StackPane();
dotPane.setLayoutX(startPosX - radius);
dotPane.setLayoutY(startPosY - radius);
Circle dot = new Circle();
dot.setRadius(radius);
dot.setFill(color);
dotPane.setCursor(Cursor.MOVE);
// dot.setStyle("-fx-fill:" + color +
// ";-fx-stroke-width:2px;-fx-stroke:black;");
dot.setCenterX(startPosX);
dot.setCenterY(startPosY);
Label txt = new Label(text);
txt.setStyle("-fx-font-size:12px;-fx-font-weight:bold;-fx-text-fill:white;");
txt.setMouseTransparent(true);
Text txt2 = new Text(dotPane.getLayoutX() - dot.getRadius() / 2, dotPane.getLayoutY() + dot.getRadius() * 1.5,
position);
txt2.setStyle("-fx-font-size:12px;-fx-font-weight:bold;");
dotPane.getChildren().addAll(dot, txt);
dotPane.setPrefSize(paneSize, paneSize);
dotPane.setMaxSize(paneSize, paneSize);
dotPane.setMinSize(paneSize, paneSize);
dotPane.setOnMousePressed(e -> {
sceneX = e.getSceneX();
sceneY = e.getSceneY();
layoutX = dotPane.getLayoutX();
layoutY = dotPane.getLayoutY();
});
EventHandler<MouseEvent> dotOnMouseDraggedEventHandler = e -> {
// Offset of drag
double offsetX = e.getSceneX() - sceneX;
double offsetY = e.getSceneY() - sceneY;
// Taking parent bounds
Bounds parentBounds = dotPane.getParent().getLayoutBounds();
// Drag node bounds
double currPaneLayoutX = dotPane.getLayoutX();
double currPaneWidth = dotPane.getWidth();
double currPaneLayoutY = dotPane.getLayoutY();
double currPaneHeight = dotPane.getHeight();
if ((currPaneLayoutX + offsetX < fieldWidth - currPaneWidth) && (currPaneLayoutX + offsetX > -1)) {
// If the dragNode bounds is within the parent bounds, then you can set the
// offset value.
dotPane.setTranslateX(offsetX);
} else if (currPaneLayoutX + offsetX < 0) {
// If the sum of your offset and current layout position is negative, then you
// ALWAYS update your translate to negative layout value
// which makes the final layout position to 0 in mouse released event.
dotPane.setTranslateX(-currPaneLayoutX);
} else {
// If your dragNode bounds are outside parent bounds,ALWAYS setting the
// translate value that fits your node at end.
dotPane.setTranslateX(fieldWidth - currPaneLayoutX - currPaneWidth);
}
if ((currPaneLayoutY + offsetY < fieldHeight - currPaneHeight) && (currPaneLayoutY + offsetY > -1)) {
dotPane.setTranslateY(offsetY);
} else if (currPaneLayoutY + offsetY < 0) {
dotPane.setTranslateY(-currPaneLayoutY);
} else {
dotPane.setTranslateY(fieldHeight - currPaneLayoutY - currPaneHeight);
}
};
dotPane.setOnMouseDragged(dotOnMouseDraggedEventHandler);
dotPane.setOnMouseReleased(e -> {
// Updating the new layout positions
dotPane.setLayoutX(layoutX + dotPane.getTranslateX());
dotPane.setLayoutY(layoutY + dotPane.getTranslateY());
// Resetting the translate positions
dotPane.setTranslateX(0);
dotPane.setTranslateY(0);
Properties rotationProp = new Properties();
String rotationProperties = "rotation.properties";
try (InputStream input = new FileInputStream(rotationProperties)) {
// load a properties file
rotationProp.load(input);
} catch (IOException ex) {
ex.printStackTrace();
}
try (OutputStream output = new FileOutputStream(rotationProperties)) {
if (position.equals("start")) {
rotationProp.setProperty(text + "StartPosX", String.valueOf(dotPane.getLayoutX()+radius));
rotationProp.setProperty(text + "StartPosY", String.valueOf(dotPane.getLayoutY()+radius));
} else {
rotationProp.setProperty(text + "TargetPosX", String.valueOf(dotPane.getLayoutX()+radius));
rotationProp.setProperty(text + "TargetPosY", String.valueOf(dotPane.getLayoutY()+radius));
}
rotationProp.store(output, null);
output.close();
} catch (IOException io) {
io.printStackTrace();
}
});
return dotPane;
}
public static void main(String[] args) {
Application.launch(args);
}
}