[英]How to drag a `Shape` that is below anther `shape` in JavaFX scene graph?
我正在使用JavaFX編寫一個教育應用程序,用戶可以在其中繪制和操作Bezier曲線Line
, QuadCurve
和CubicCurve
。 這些曲線應該能夠用鼠標拖動。 我有兩種選擇:
1-使用Line
, QuadCurve
和CubicCurve
,然后用透明顏色填充它們,並用另一種顏色描繪它們,比如黑色。 此選項出現的問題是用戶想要拖動曲線,但會看到拖動另一條曲線。 這樣做的原因是用戶要拖動的曲線位於場景圖中的另一個曲線下方。 例如,在下圖中,較小的曲線不能拖動,因為它低於場景圖中較大的曲線。
2-使用類javafx.scene.shape.Path
,在這種情況下問題是操縱這樣的路徑有點復雜,因為它由一些PathElement
組成,並且簡單地操作元素不會改變Path
,除非我們從其elements屬性中刪除一個元素,並添加一個新元素。 因此,我更喜歡方法1。
我怎樣才能克服第一種方法中出現的問題?
預先感謝您的幫助。 我的程序代碼的簡化版本如下。
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.CubicCurve;
import javafx.scene.shape.QuadCurve;
import javafx.stage.Stage;
public class SampleForStackOverflow extends Application
{
double lastMouseX;
double lastMouseY;
double lastTranslateX;
double lastTranslateY;
@Override
public void start(Stage window)
{
final double STROKE_WIDTH = 5;
QuadCurve quad = new QuadCurve(100, 200, 150, 50, 200, 200);
quad.setFill(Color.TRANSPARENT);
quad.setStroke(Color.BLACK);
quad.setStrokeWidth(STROKE_WIDTH);
quad.setOnMousePressed(e -> {
lastMouseX = e.getSceneX();
lastMouseY = e.getSceneY();
lastTranslateX = quad.getTranslateX();
lastTranslateY = quad.getTranslateY();
});
quad.setOnMouseDragged(e -> followMouse(quad, e));
CubicCurve cubic = new CubicCurve(0, 300, 100, 0, 300, 0, 300, 300);
cubic.setFill(Color.TRANSPARENT);
cubic.setStroke(Color.BLACK);
cubic.setStrokeWidth(STROKE_WIDTH);
cubic.setOnMousePressed(e -> {
lastMouseX = e.getSceneX();
lastMouseY = e.getSceneY();
lastTranslateX = cubic.getTranslateX();
lastTranslateY = cubic.getTranslateY();
});
cubic.setOnMouseDragged(e -> followMouse(cubic, e));
Group root = new Group(quad, cubic);
Scene scene = new Scene(root, 500, 500);
window.setScene(scene);
window.show();
}
private void followMouse(Node node, MouseEvent e)
{
double deltaX = e.getSceneX() - lastMouseX;
double deltaY = e.getSceneY() - lastMouseY;
node.setTranslateX(deltaX + lastTranslateX);
node.setTranslateY(deltaY + lastTranslateY);
}
public static void main(String[] args) {
launch(args);
}
}
您應該明確地將曲線的填充顏色設置為null並將pickOnBounds設置為false,而不是在第一個場景中使用透明顏色。 透明顏色仍將捕獲鼠標事件但null不會捕獲,而當pickOnBounds為false時,僅當您正好在形狀的彩色部分上時才會捕獲鼠標事件。
使用Paths創建QuadCurve和CubicCurve似乎對我來說很好。 這是一個完整的例子:
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.QuadCurveTo;
import javafx.stage.Stage;
public class SampleForStackOverflow extends Application {
private final double STROKE_WIDTH = 5;
private double lastMouseX;
private double lastMouseY;
private double lastTranslateX;
private double lastTranslateY;
@Override
public void start(Stage window) {
Path quad = initQuadCurve(100, 200, 200, 200, 150, 50);
Path cubic = initCubicCurve(0, 300, 300, 300, 100, 0, 300, 0);
Pane root = new Pane(cubic, quad);
Scene scene = new Scene(root, 500, 500);
window.setScene(scene);
window.show();
}
private Path initQuadCurve(int xStart, int yStart, int xEnd, int yEnd, int controlX, int controlY) {
Path curvePath = new Path();
curvePath.setStrokeWidth(STROKE_WIDTH);
MoveTo moveTo = new MoveTo(xStart, yStart);
QuadCurveTo quadTo = new QuadCurveTo();
quadTo.setControlX(controlX);
quadTo.setControlY(controlY);
quadTo.setX(xEnd);
quadTo.setY(yEnd);
curvePath.getElements().addAll(moveTo, quadTo);
curvePath.setOnMousePressed(e -> {
lastMouseX = e.getSceneX();
lastMouseY = e.getSceneY();
lastTranslateX = curvePath.getTranslateX();
lastTranslateY = curvePath.getTranslateY();
});
curvePath.setOnMouseDragged(e -> followMouse(curvePath, e));
return curvePath;
}
private Path initCubicCurve(int xStart, int yStart, int xEnd, int yEnd, int x1Control, int y1Control, int x2Control,
int y2Control) {
Path curvePath = new Path();
curvePath.setStrokeWidth(STROKE_WIDTH);
MoveTo moveTo = new MoveTo(xStart, yStart);
CubicCurveTo cubicTo = new CubicCurveTo();
cubicTo.setControlX1(x1Control);
cubicTo.setControlY1(y1Control);
cubicTo.setControlX2(x2Control);
cubicTo.setControlY2(y2Control);
cubicTo.setX(xEnd);
cubicTo.setY(yEnd);
curvePath.getElements().addAll(moveTo, cubicTo);
curvePath.setOnMousePressed(e -> {
lastMouseX = e.getSceneX();
lastMouseY = e.getSceneY();
lastTranslateX = curvePath.getTranslateX();
lastTranslateY = curvePath.getTranslateY();
});
curvePath.setOnMouseDragged(e -> followMouse(curvePath, e));
return curvePath;
}
private void followMouse(Node node, MouseEvent e) {
double deltaX = e.getSceneX() - lastMouseX;
double deltaY = e.getSceneY() - lastMouseY;
node.setTranslateX(deltaX + lastTranslateX);
node.setTranslateY(deltaY + lastTranslateY);
}
public static void main(String[] args) {
launch(args);
}
}
說實話,我的第一次嘗試是調用quad.setPickOnBounds(false);
(以及對於立方體而言)如以下兩個帖子所示:
JavaFX通過透明節點將MouseEvents傳遞給子節點
但是它不起作用或者我錯過了一些東西,但是如果自己創造路徑,那么就不必再復雜化了。 在任何情況下,如果您想要遵循第一種方法,我建議您查看鏈接。 如果您要遵循第二種方法,操縱路徑在我看來並不會非常困難。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.