当前位置: 首页 > 知识库问答 >
问题:

JavaFX画布绘制

景才英
2023-03-14

我目前正在使用画布开发一个JavaFX-Drawing-Application。在GraphicsContext的帮助下,我使用beginPath()和lineTo()方法绘制线条,但我无法找到实现橡皮擦的适当方法。

package GUI;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class Main extends Application {

    private final int mouseOffset = 60;

    private Stage window;
    private Canvas canvas;
    private GraphicsContext gc;

    @Override
    public void start(Stage primaryStage) {
        window = primaryStage;
        window.setTitle("Drawing Board ~ by Michael Holley");
        window.setX(100);
        window.setY(100);
        window.setResizable(false);
        window.setOnCloseRequest(e -> {
            Platform.exit();
            System.exit(0);
        });
        BorderPane layout = new BorderPane();

        /* OPTION PANE */
        HBox optionPane = new HBox();
        optionPane.setPrefHeight(60);
        optionPane.setSpacing(10);
        optionPane.setPadding(new Insets(10, 10, 10, 10));
        optionPane.setAlignment(Pos.CENTER);
        ColorPicker colorSelection = new ColorPicker();
        colorSelection.setValue(Color.CORNFLOWERBLUE);
        colorSelection.setOnAction(actionEvent -> {
            gc.setFill(colorSelection.getValue());
            gc.setStroke(colorSelection.getValue());
        });
        optionPane.getChildren().add(colorSelection);

        Slider sizeSlider = new Slider();
        sizeSlider.setMin(1);
        sizeSlider.setMax(50);
        sizeSlider.setValue(18);
        optionPane.getChildren().add(sizeSlider);

        TextField sizeSliderTF = new TextField();
        sizeSliderTF.setEditable(false);
        sizeSliderTF.setText(String.format("%.0f", sizeSlider.getValue()));
        sizeSliderTF.setPrefWidth(30);
        sizeSliderTF.setAlignment(Pos.CENTER);
        sizeSlider.valueProperty().addListener((observableValue, oldNumber, newNumber) -> {
            sizeSlider.setValue(newNumber.intValue());
            sizeSliderTF.setText(String.format("%.0f", sizeSlider.getValue()));
            gc.setLineWidth(sizeSlider.getValue());
        });
        optionPane.getChildren().add(sizeSliderTF);

        Separator optionPaneSeparator_1 = new Separator();
        optionPaneSeparator_1.setOrientation(Orientation.VERTICAL);
        optionPane.getChildren().add(optionPaneSeparator_1);

        final ToggleGroup group = new ToggleGroup();
        RadioButton drawButton = new RadioButton("Draw");
        drawButton.setToggleGroup(group);
        drawButton.setSelected(true);
        RadioButton eraseButton = new RadioButton("Erase");
        eraseButton.setToggleGroup(group);
        optionPane.getChildren().addAll(drawButton, eraseButton);

        Separator optionPaneSeparator_2 = new Separator();
        optionPaneSeparator_2.setOrientation(Orientation.VERTICAL);
        optionPane.getChildren().add(optionPaneSeparator_2);

        Button clearButton = new Button("Clear");
        clearButton.setOnAction(actionEvent -> gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight()));
        optionPane.getChildren().add(clearButton);

        Button fillButton = new Button("Fill");
        fillButton.setOnAction(actionEvent -> gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight()));
        optionPane.getChildren().add(fillButton);
        layout.setTop(optionPane);


        /* CANVAS */
        canvas = new Canvas(800, 740);
        gc = canvas.getGraphicsContext2D();
        gc.setStroke(colorSelection.getValue());
        gc.setFill(colorSelection.getValue());
        gc.setLineWidth(sizeSlider.getValue());

        canvas.setOnMousePressed(mouseEvent -> {
            if (drawButton.isSelected() && !eraseButton.isSelected()) {
                gc.beginPath();
                gc.lineTo(mouseEvent.getSceneX(), mouseEvent.getSceneY() - mouseOffset);
                gc.stroke();
            } else if (!drawButton.isSelected() && eraseButton.isSelected()) {
                double currentSize = sizeSlider.getValue();
                gc.clearRect(mouseEvent.getSceneX() - currentSize / 2, mouseEvent.getSceneY() - currentSize / 2 - mouseOffset, currentSize, currentSize);
            }
        });

        canvas.setOnMouseDragged(mouseEvent -> {
            if (drawButton.isSelected() && !eraseButton.isSelected()) {
                gc.lineTo(mouseEvent.getSceneX(), mouseEvent.getSceneY() - mouseOffset);
                gc.stroke();
            } else if (!drawButton.isSelected() && eraseButton.isSelected()) {
                double currentSize = sizeSlider.getValue();
                gc.clearRect(mouseEvent.getSceneX() - currentSize / 2, mouseEvent.getSceneY() - currentSize / 2 - mouseOffset, currentSize, currentSize);
            }
        });

        layout.setCenter(canvas);


        Scene scene = new Scene(layout, 800, 800);
        scene.getStylesheets().add("GUI/OptionsStyling.css");
        window.setScene(scene);
        window.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}


共有1个答案

缑兴贤
2023-03-14

这是个棘手的问题。看来除了clearRect方法之外,没有其他方法可以清除图形。(甚至我尝试的一些混合模式和基于剪辑的攻击也没有成功。)

您可以使用clearRect绘制每个线段,如果您先临时旋转图形上下文:

import javafx.geometry.Point2D;
import javafx.scene.transform.Affine;
import javafx.scene.transform.Rotate;

// ...

private Point2D lastErasePoint;

// ...

    canvas.setOnMousePressed(mouseEvent -> {
        if (drawButton.isSelected() && !eraseButton.isSelected()) {
            gc.beginPath();
            gc.lineTo(mouseEvent.getSceneX(), mouseEvent.getSceneY() - mouseOffset);
            gc.stroke();
        } else if (!drawButton.isSelected() && eraseButton.isSelected()) {
            lastErasePoint = new Point2D(
                mouseEvent.getSceneX(), mouseEvent.getSceneY() - mouseOffset);
        }
    });

    canvas.setOnMouseDragged(mouseEvent -> {
        if (drawButton.isSelected() && !eraseButton.isSelected()) {
            gc.lineTo(mouseEvent.getSceneX(), mouseEvent.getSceneY() - mouseOffset);
            gc.stroke();
        } else if (!drawButton.isSelected() && eraseButton.isSelected()) {
            Point2D location = new Point2D(
                mouseEvent.getSceneX(), mouseEvent.getSceneY() - mouseOffset);

            Point2D diff = location.subtract(lastErasePoint);
            double angle = Math.toDegrees(
                Math.atan2(diff.getY(), diff.getX()));
            double width = gc.getLineWidth();

            gc.save();
            gc.setTransform(new Affine(new Rotate(
                angle, lastErasePoint.getX(), lastErasePoint.getY())));
            gc.clearRect(
                lastErasePoint.getX() - width / 2,
                lastErasePoint.getY() - width / 2,
                lastErasePoint.distance(location) + width, width);
            gc.restore();

            lastErasePoint = location;
        }
    });
 类似资料:
  • 我编写了这段代码,可以在JavaFX画布上绘制。它可以很好地工作,但我不知道如何重新绘制画布(比如在Swing中),以便在新画布上重新开始绘制。这是我的代码,非常感谢你的帮助!马里奥

  • 我正在考虑将我们内部的汽车/测量应用程序从Swing移植到JavaFX,主要是因为它有更好的外观和多点触控支持,但是我找不到一种方法来渲染只有当它们可见时才可以呈现的自定义组件。 为了获得动力,想象一个有10个选项卡的屏幕,每个选项卡内都有一个显示正在测量的一些实时数据的图。任何时候,只能看到一个情节。数据量很大,计算机有足够的能力一次渲染一个情节,但不能同时渲染所有情节。 摇摆版 现在在Swin

  • 我可以绘制图像,但我如何旋转该图像例如45度并绘制它,然后绘制另一个图像与-50度旋转在同一画布? 不适用于我,因为它会旋转所有画布内容。

  • 在这个例子中我们将使用画布(Canvas)创建一个简单的绘制程序。 在我们场景的顶部我们使用行定位器排列四个方形的颜色块。一个颜色块是一个简单的矩形,使用鼠标区域来检测点击。 Row { id: colorTools anchors { horizontalCenter: parent.horizontalCenter

  • 我想在HTML5画布/或SVG上执行以下操作: 有一个背景路径,将光标移过去并绘制(填充)背景路径 用户完成绘图后有回调函数 我的问题是,我不知道如何检查抽屉线是否遵循路径。 有人能给我解释一下如何做到这一点,或者给我一些建议吗? http://jsbin.com/reguyuxawo/edit?html,js,控制台,输出

  • 我有这个方法在JavaFX中使用canvas绘制笛卡尔平面 这是我的密码http://postimg.org/image/uipe1mgyb/的抽屉 我想举一个http://postimg.org/image/98k9mvnb3/例子 在另一篇文章中,他们建议我使用PixelWriter在Canvas中写入像素。我试过了,但它什么也没做。 我认为我在JavaFX中使用画布绘制笛卡尔平面的方法是不正