JavaFX удаляет последний нарисованный объект с холста
Вступление:
Я создал холст, и моя цель - создать круги в том месте, где вы нажимаете на холсте. Но я также хочу иметь возможность удалить нарисованные круги или, по крайней мере, последний нарисованный круг. Перерисовка в том же месте, где круг с цветом фона, не является хорошим решением. Потому что если в круге есть другие вещи, они также будут удалены. Например, в этом приложении 2 круга могут иметь пересечение, и когда вы попытаетесь удалить 2-й круг, эти точки пересечения будут пустыми, что будет означать также удаление некоторой части первого круга. Поэтому я подумал о создании 2-го холста. И каждый раз, когда я щелкаю где-нибудь на холсте, перед тем как нарисовать круг, я назначаю основной холст резервному холсту. И когда я хочу удалить последний нарисованный объект, я могу загрузить резервную копию холста.
Теперь я попытался сделать то, что объяснил выше, и не смог заставить его работать так, как я намеревался. На самом деле я даже видел некоторые странные (по крайней мере для меня) поведения в других вещах.
В основном я создал 2 холста одинакового размера.
public class Main extends Application {
double ldx, ldy, diameter;
Canvas lastCanvas = new Canvas(800,600);
Canvas pane1 = new Canvas(800,600);
@Override
public void start(Stage primaryStage) throws Exception{
System.out.println("Hello");
HBox root = new HBox();
GraphicsContext gc = pane1.getGraphicsContext2D();
pane1.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
// Draw circle around x,y
lastCanvas = pane1;
diameter = 25.0;
ldx = event.getSceneX() - ( diameter/2 );
ldy = event.getSceneY() - ( diameter/2 );
gc.strokeOval(ldx, ldy, diameter, diameter);
System.out.println("Clicked");
}
});
VBox pane2 = new VBox(10);
pane2.setPrefSize(224,600);
Button button1 = new Button("Clear Last Drawn");
button1.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
pane1 = lastCanvas;
System.out.println("Last canvas loaded");
}
});
pane2.getChildren().addAll(button1);
pane1.setStyle("-fx-background-color: #224488");
pane2.setStyle("-fx-background-color: #224488");
root.getChildren().addAll(pane1, pane2);
Scene scene1 = new Scene(root, 1024, 600);
primaryStage.setScene(scene1);
primaryStage.setTitle("Mouse Clicker");
primaryStage.show();
}
}
Ожидаемое поведение заключается в том, что каждый раз, когда я нажимаю на кнопку, он загружает lastCanvas, который является холстом перед тем, как я нарисовал последний объект. Но это не так. Я попробовал что-то вроде этого в mouseevent button1
root.getChildren().removeAll();
root.getChildren().addAll(lastCanvas, pane2);
Который генерирует ошибку на консоли каждый раз, когда вы нажимаете кнопку. Другая проблема заключается в том, что я пытался создать 2-ю сцену.
HBox root2 = new HBox();
root2.getChildren().addAll(lastCanvas, pane2);
Это неожиданно удаляет все на панели 2, хотя я нигде не использую root2. Все, что я делаю здесь, это создание нового HBox и добавление pane2 в этот hbox. Почему при этом удаляется pane2 из моего primaryStage, а не остается пустое пространство?
Кроме того, если у вас есть другие рекомендации по удалению последнего объекта, нарисованного на холсте - или до тех пор, пока холст не станет полностью пустым - вы также можете сказать мне об этом, вместо того чтобы пытаться решить, что я сделал неправильно в приведенном выше коде.
3 ответа
Не анализируя проблему, я предлагаю следующее решение, используя ваш код в качестве основы
private final double diameter = 25;
private final LinkedList<Point2D> centers = new LinkedList<>();
private final Canvas pane1 = new Canvas(800, 600);
@Override
public void start(Stage primaryStage) throws Exception
{
System.out.println("Hello");
HBox root = new HBox();
pane1.setOnMouseClicked((MouseEvent event) ->
{
centers.add(new Point2D(event.getSceneX(), event.getSceneY()));
render();
System.out.println("Clicked");
});
VBox pane2 = new VBox(10);
pane2.setPrefSize(224, 600);
Button button1 = new Button("Clear Last Drawn");
button1.setOnMouseClicked((MouseEvent event) ->
{
if (!centers.isEmpty())
{
centers.removeLast();
render();
System.out.println("Last canvas loaded");
}
});
pane2.getChildren().addAll(button1);
pane1.setStyle("-fx-background-color: #224488");
pane2.setStyle("-fx-background-color: #224488");
root.getChildren().addAll(pane1, pane2);
Scene scene1 = new Scene(root, 1024, 600);
primaryStage.setScene(scene1);
primaryStage.setTitle("Mouse Clicker Project (Berk YATKIN)");
primaryStage.show();
}
private void render()
{
pane1.getGraphicsContext2D().clearRect(0, 0, pane1.getWidth(), pane1.getHeight());
centers.forEach((p) ->
{
pane1.getGraphicsContext2D().strokeOval(
p.getX() - (diameter / 2),
p.getY() - (diameter / 2),
diameter,
diameter);
});
}
Вы просили об этом, поэтому вот оно:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
BorderPane root = new BorderPane();
Pane graphicsPane = new Pane();
root.setCenter(graphicsPane);
graphicsPane.setOnMouseClicked(e -> {
// Draw circle around x,y
Circle circle = new Circle(e.getX(), e.getY(), 50.0);
circle.setStroke(Color.RED);
circle.setStrokeWidth(4.0);
circle.setFill(null);
graphicsPane.getChildren().add(circle);
});
VBox pane2 = new VBox(10);
pane2.setPrefWidth(224);
Button button1 = new Button("Clear Last Drawn");
button1.setOnAction(e -> {
int numCircles = graphicsPane.getChildren().size();
if (numCircles > 0) {
graphicsPane.getChildren().remove(numCircles - 1);
}
});
pane2.getChildren().addAll(button1);
root.setRight(pane2);
graphicsPane.setStyle("-fx-background-color: #aaaaaa");
pane2.setStyle("-fx-background-color: #224488");
Scene scene1 = new Scene(root, 1024, 600);
primaryStage.setScene(scene1);
primaryStage.setTitle("Mouse Clicker");
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Это решение с использованием графа сцены напрямую. Этот пример также может быть легко расширен для перемещения окружностей по кругу или удаления круга с помощью графического выделения. Все вещи, которые не легко возможны с холстом.
Также, не анализируя проблему, я сначала задам вопрос, почему вы настаиваете на использовании холста. Граф сцены гораздо больше подходит для такого рода задач. Вы можете добавить (почти) любое количество кругов и удалить столько их, сколько хотите в любом порядке. Что могло быть проще этого?