尝试在 JavaFX 中切换 GraphicsContext 的上下文
Trying to switch the context of GraphicsContext in JavaFX
我正在使用 JavaFX 创建一个小型绘图程序。我已经在 canvas 上成功实现了免费绘图。但是,我还希望能够从我单击的点到按下鼠标时绘制直线。我事先创建了一条线,但是我似乎无法切换上下文,所以我只会画直线而不是自由绘图。
目前,如果我点击我的 "straight line" 按钮,它会绘制一条直线,然后默认返回自由绘图,同时抛出很多错误。你能帮忙吗?
这是我的免费绘图代码:
paintScene.setOnMousePressed(e -> {
gc.beginPath();
gc.lineTo(e.getSceneX(), e.getSceneY());
gc.stroke();
});
paintScene.setOnMouseDragged(e -> {
gc.lineTo(e.getSceneX(), e.getSceneY());
gc.stroke();
});
(其中 gc 是 GraphicsContext)
这是我创建直线的功能:
Line l = new Line(20, 30, 30, 20);
l.setStroke(Color.BLACK);
l.setStrokeWidth(10);
straightLineBtn.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
paintScene.setOnMousePressed(event1 -> {
canvasHolder.getChildren().addAll(l);
});
}
});
这一行
canvasHolder.getChildren().addAll(l);
尝试在每次点击时将同一行 l
添加到 canvasHolder
。
禁止将同一个组件多次添加到组件树中。您应该在每次点击时创建并添加一个新的 Line
。
您为 自由绘图 模式定义了 onMousePressed
和 onMouseDragged
处理程序,并且只为 直接替换 onMousePressed
行 模式。这会导致一些模式组合被激活,而不是纯粹的 直线 模式。要解决此问题,您应该删除 onMouseDragged
处理程序,或者以与 onMousePressed
处理程序相同的方式重新定义它。
您需要更新行,直到您松开鼠标按钮。这意味着您要么必须存储有关之前绘制的所有内容的数据,要么需要在 canvas 之上绘制 Line
Node
。我推荐后一种方法。
示例代码
private static class LineDrawListener implements EventHandler<ActionEvent> {
private LineDrawListener(Canvas canvas, Pane canvasPane) {
this.canvasPane = canvasPane;
this.gc = canvas.getGraphicsContext2D();
line = new Line();
line.setStrokeWidth(10);
line.setManaged(true);
line.setMouseTransparent(true);
releasedHandler = evt -> {
// remove line from canvas parent and draw line on canvas instead
canvasPane.getChildren().remove(line);
Point2D start = canvas.parentToLocal(line.getStartX(), line.getStartY());
Point2D end = canvas.parentToLocal(line.getEndX(), line.getEndY());
gc.setLineWidth(10);
gc.strokeLine(start.getX(), start.getY(), end.getX(), end.getY());
removeListeners();
};
draggedHandler = evt -> {
// update end of line
line.setEndX(evt.getX());
line.setEndY(evt.getY());
};
pressedHandler = evt -> {
// add line to canvas parent
canvasPane.getChildren().add(line);
line.setStartX(evt.getX());
line.setStartY(evt.getY());
line.setEndX(evt.getX());
line.setEndY(evt.getY());
};
}
private final GraphicsContext gc;
private final Pane canvasPane;
private final Line line;
private final EventHandler<MouseEvent> pressedHandler;
private final EventHandler<MouseEvent> draggedHandler;
private final EventHandler<MouseEvent> releasedHandler;
private void removeListeners() {
canvasPane.setOnMousePressed(null);
canvasPane.setOnMouseDragged(null);
canvasPane.setOnMouseReleased(null);
}
@Override
public void handle(ActionEvent event) {
canvasPane.setOnMousePressed(pressedHandler);
canvasPane.setOnMouseDragged(draggedHandler);
canvasPane.setOnMouseReleased(releasedHandler);
}
}
@Override
public void start(Stage primaryStage) {
Canvas canvas = new Canvas(400, 400);
Rectangle clip = new Rectangle();
clip.widthProperty().bind(canvas.widthProperty());
clip.heightProperty().bind(canvas.heightProperty());
Pane canvasPane = new Pane(canvas);
canvasPane.setClip(clip);
Button btn = new Button("Draw Line");
LineDrawListener listener = new LineDrawListener(canvas, canvasPane);
btn.setOnAction(listener);
VBox root = new VBox(btn, canvasPane);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
}
我正在使用 JavaFX 创建一个小型绘图程序。我已经在 canvas 上成功实现了免费绘图。但是,我还希望能够从我单击的点到按下鼠标时绘制直线。我事先创建了一条线,但是我似乎无法切换上下文,所以我只会画直线而不是自由绘图。
目前,如果我点击我的 "straight line" 按钮,它会绘制一条直线,然后默认返回自由绘图,同时抛出很多错误。你能帮忙吗?
这是我的免费绘图代码:
paintScene.setOnMousePressed(e -> {
gc.beginPath();
gc.lineTo(e.getSceneX(), e.getSceneY());
gc.stroke();
});
paintScene.setOnMouseDragged(e -> {
gc.lineTo(e.getSceneX(), e.getSceneY());
gc.stroke();
});
(其中 gc 是 GraphicsContext)
这是我创建直线的功能:
Line l = new Line(20, 30, 30, 20);
l.setStroke(Color.BLACK);
l.setStrokeWidth(10);
straightLineBtn.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
paintScene.setOnMousePressed(event1 -> {
canvasHolder.getChildren().addAll(l);
});
}
});
这一行
canvasHolder.getChildren().addAll(l);
尝试在每次点击时将同一行 l
添加到 canvasHolder
。
禁止将同一个组件多次添加到组件树中。您应该在每次点击时创建并添加一个新的 Line
。
您为 自由绘图 模式定义了 onMousePressed
和 onMouseDragged
处理程序,并且只为 直接替换 onMousePressed
行 模式。这会导致一些模式组合被激活,而不是纯粹的 直线 模式。要解决此问题,您应该删除 onMouseDragged
处理程序,或者以与 onMousePressed
处理程序相同的方式重新定义它。
您需要更新行,直到您松开鼠标按钮。这意味着您要么必须存储有关之前绘制的所有内容的数据,要么需要在 canvas 之上绘制 Line
Node
。我推荐后一种方法。
示例代码
private static class LineDrawListener implements EventHandler<ActionEvent> {
private LineDrawListener(Canvas canvas, Pane canvasPane) {
this.canvasPane = canvasPane;
this.gc = canvas.getGraphicsContext2D();
line = new Line();
line.setStrokeWidth(10);
line.setManaged(true);
line.setMouseTransparent(true);
releasedHandler = evt -> {
// remove line from canvas parent and draw line on canvas instead
canvasPane.getChildren().remove(line);
Point2D start = canvas.parentToLocal(line.getStartX(), line.getStartY());
Point2D end = canvas.parentToLocal(line.getEndX(), line.getEndY());
gc.setLineWidth(10);
gc.strokeLine(start.getX(), start.getY(), end.getX(), end.getY());
removeListeners();
};
draggedHandler = evt -> {
// update end of line
line.setEndX(evt.getX());
line.setEndY(evt.getY());
};
pressedHandler = evt -> {
// add line to canvas parent
canvasPane.getChildren().add(line);
line.setStartX(evt.getX());
line.setStartY(evt.getY());
line.setEndX(evt.getX());
line.setEndY(evt.getY());
};
}
private final GraphicsContext gc;
private final Pane canvasPane;
private final Line line;
private final EventHandler<MouseEvent> pressedHandler;
private final EventHandler<MouseEvent> draggedHandler;
private final EventHandler<MouseEvent> releasedHandler;
private void removeListeners() {
canvasPane.setOnMousePressed(null);
canvasPane.setOnMouseDragged(null);
canvasPane.setOnMouseReleased(null);
}
@Override
public void handle(ActionEvent event) {
canvasPane.setOnMousePressed(pressedHandler);
canvasPane.setOnMouseDragged(draggedHandler);
canvasPane.setOnMouseReleased(releasedHandler);
}
}
@Override
public void start(Stage primaryStage) {
Canvas canvas = new Canvas(400, 400);
Rectangle clip = new Rectangle();
clip.widthProperty().bind(canvas.widthProperty());
clip.heightProperty().bind(canvas.heightProperty());
Pane canvasPane = new Pane(canvas);
canvasPane.setClip(clip);
Button btn = new Button("Draw Line");
LineDrawListener listener = new LineDrawListener(canvas, canvasPane);
btn.setOnAction(listener);
VBox root = new VBox(btn, canvasPane);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
}