【问题标题】:JavaFX: Draw a rectangle on canvas based on 2 mouse clicksJavaFX:基于 2 次鼠标点击在画布上绘制一个矩形
【发布时间】:2019-12-30 17:04:06
【问题描述】:

我正在尝试创建一个程序,该程序应基于两次鼠标左键单击在画布上绘制一个矩形,并单击一次右键清除画布。

矩形的创建方式应该是,第一次鼠标单击模拟矩形的一个角,与第一次鼠标单击相比,下一次鼠标单击模拟矩形的对角角。

我不知道如何存储第一次鼠标单击的坐标,然后充分利用第二次鼠标单击,因为每个定义的矩形仅基于一组坐标创建,即上-矩形的左角。

现在,我的代码所做的只是绘制固定大小的矩形 (50x25),这显然不是我想要的。这只是为了看看清除部分是否有效。

这是我目前得到的:

package application;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class DrawRectangle extends Application {

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

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Title");
        Canvas canv = new Canvas(500, 400);
        GraphicsContext gc = canv.getGraphicsContext2D();

        EventHandler<MouseEvent> event = new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                if (event.getButton() == MouseButton.PRIMARY) {
                    double x = event.getX();
                    double y = event.getY();                    
                    gc.setFill(Color.BLUE);
                    gc.fillRect(x, y, 50, 25);
                }
            }
        };

        canv.addEventHandler(MouseEvent.MOUSE_CLICKED, event);

        EventHandler<MouseEvent> event2 = new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event2) {
                if (event2.getButton() == MouseButton.SECONDARY) {
                gc.clearRect(0, 0, 500, 400);
                }
            }
        };

        canv.addEventHandler(MouseEvent.MOUSE_CLICKED, event2);

        StackPane root = new StackPane();
        root.getChildren().add(canv);

        primaryStage.setScene(new Scene(root, 500, 400));
        primaryStage.show();
    }
}

我不知道鼠标点击应该模拟矩形的哪个角是否重要,也许有人有任何想法?

最好的问候和新年快乐

【问题讨论】:

    标签: java javafx canvas drawing rectangles


    【解决方案1】:

    只需将第一个点击点保存在成员变量中,然后在用户进行第二个点击点时使用并重置它。

    注意:下面的示例代码使用 Java 13+ 中的 switch expression。如果您的 Java 版本中没有 switch 表达式,请将其转换为标准 switch 语句或 if/else 子句。

    import javafx.application.Application;
    import javafx.geometry.*;
    import javafx.scene.Scene;
    import javafx.scene.canvas.*;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.layout.StackPane;
    import javafx.scene.paint.Color;
    import javafx.stage.Stage;
    
    public class DrawRectangle extends Application {
    
        private static final int W = 500;
        private static final int H = 400;
    
        private Point2D savedPoint = null;
    
        @Override
        public void start(Stage stage) {
            Canvas canvas = new Canvas(W, H);
            GraphicsContext gc = canvas.getGraphicsContext2D();
    
            canvas.setOnMouseClicked(event -> {
                switch (event.getButton()) {
                    case PRIMARY   -> handlePrimaryClick(gc, event);
                    case SECONDARY -> gc.clearRect(0, 0, W, H);
                }
            });
    
            stage.setResizable(false);
            stage.setScene(new Scene(new StackPane(canvas), W, H));
            stage.show();
        }
    
        private void handlePrimaryClick(GraphicsContext gc, MouseEvent event) {
            Point2D clickPoint = new Point2D(event.getX(), event.getY());
    
            if (savedPoint == null) {
                savedPoint = clickPoint;
            } else {
                Rectangle2D rectangle2D = getRect(savedPoint, clickPoint);
    
                gc.setFill(Color.BLUE);
                gc.fillRect(
                        rectangle2D.getMinX(),
                        rectangle2D.getMinY(),
                        rectangle2D.getWidth(),
                        rectangle2D.getHeight()
                );
    
                savedPoint = null;
            }
        }
    
        private Rectangle2D getRect(Point2D p1, Point2D p2) {
            return new Rectangle2D(
                    Math.min(p1.getX(), p2.getX()),
                    Math.min(p1.getY(), p2.getY()),
                    Math.abs(p1.getX() - p2.getX()),
                    Math.abs(p1.getY() - p2.getY())
            );
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    【讨论】:

    • 这正是我要找的!非常感谢 - 新年快乐!我不太熟悉switch语句和初始化/实例化(?)event的语法以及第22行-&gt;的使用。您可以详细说明吗?我已经使它适用于 if 语句,因为这些 switch 语句不适用于我的 Java 版本。
    • 我在答案中提供了一个链接,说明switch expressions 是什么以及替代方案是什么,请阅读。鼠标点击事件的事件处理语法是lambda expression,为此我还在此评论中链接了一个教程(特别是阅读教程中标题为“GUI 应用程序中的 Lambda 表达式”的部分)。它不是初始化/实例化一个事件(该事件已经由 JavaFX 创建),它是为相关事件定义一个处理程序。
    • 你帮了大忙。 Lambda 表达式使代码更加简洁、优雅和可读!谢谢。
    猜你喜欢
    • 2016-03-04
    • 1970-01-01
    • 1970-01-01
    • 2019-12-11
    • 2021-08-18
    • 2013-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多