尝试使用JavaFX使用鼠标创建形状

时间:2017-10-24 14:25:39

标签: java javafx

我正在尝试创建一个Java应用程序,该应用程序使用JavaFX允许用户通过选择单选按钮选项创建形状,然后在BorderPane区域中单击并拖动以创建其形状。

到目前为止,我正走在正确的轨道上。我遇到的问题是让它们正确定位。我希望有人可以帮我弄清楚为什么没有在我期望的地方创造形状。

目前,我创建的第一个形状放置在我在BorderPane的Center部分的HBox的左上角,无论我在哪里点击开始创建。拖动鼠标似乎可以根据光标准确地调整框的大小。

创建形状的后续尝试会导致在光标的位置外创建形状,并且拖动将调整大小,但也不会与光标相关联。

这是我的代码。我已经拿出了与手头问题无关的部分,希望能让它更具可读性:

public class Main extends Application{
    public static String shapeType = "";
    public static String color = "";

    static Rectangle customRectangle = null;

    public void start(Stage mainStage) throws Exception{
        Group root = new Group();
        Scene scene = new Scene(root, 600, 400);

        BorderPane borderPane = new BorderPane();

        .....

        HBox canvas = new HBox();
        Group canvasGroup = new Group();
        canvas.getChildren().add(canvasGroup);

        canvas.setStyle("-fx-background-color: yellow");

        borderPane.setTop(shapeOptions);
        borderPane.setLeft(colorOptions);
        borderPane.setCenter(canvas);

        canvas.addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                if(event.getEventType() == MouseEvent.MOUSE_PRESSED && shapeType != ""){
                    switch(shapeType){
                        case "rectangle":
                            createCustomRectangle(event, color, canvasGroup);
                    }
                }
                if(event.getEventType() == MouseEvent.MOUSE_DRAGGED){
                    switch (shapeType){
                        case "rectangle":
                            editCustomRectangle(event);
                    }
                }
            }
        });

        root.getChildren().add(borderPane);
        mainStage.setScene(scene);
        mainStage.show();
    }

    public static void createCustomRectangle(MouseEvent event, String color, Group canvasGroup){
        customRectangle = new Rectangle(0, 0, 10,10);
        customRectangle.relocate(event.getX(), event.getY());

        customRectangle.setFill(Color.RED);
        canvasGroup.getChildren().add(customRectangle);
    }

    public static void editCustomRectangle(MouseEvent event){
        customRectangle.setWidth(event.getX() - customRectangle.getTranslateX());
        customRectangle.setHeight(event.getY() - customRectangle.getTranslateY());
    }

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

我还想附上一些图片,以便让我的问题更清晰。这是尝试创建第一个形状: Clicking and dragging to create first shape

这里是尝试创建一个后续形状: Clicking and dragging to create another shape

希望描述,代码和图像足以传达正在发生的事情。任何帮助将不胜感激。

谢谢!

3 个答案:

答案 0 :(得分:2)

让我们一次开始解决每个问题。首先是一个友好的建议,尝试以一种帮助读者理解其含义和身份的方式命名变量(当我第一次看到canvas变量时,我认为它是一个真正的Canvas)。

现在您的布局是这样的:

BorderPane 
    TOP 
        - Something
    CENTER 
        - HBox
            - Group
                - Rectangle
                - Rectangle
                - ...
    Left
        - Something
    Bottom 
        - Something
  1. HBox取得所有可用的高度,并根据其子项计算宽度。所以为了拿走所有的 您需要实际指定BorderPane中的可用空间或将其preferredWidthProperty绑定到 BorderPane的widthProperty。

  2. 从Group类的文档中可以看到:

  3.   

    应用于组的任何转换,效果或状态都将应用于   该群体的所有孩子。这样的变换和效果不会   但是,如果转换和包含在此组的布局范围内   效果直接设定在本集团的子女身上   包含在本集团的布局范围内。

    因此,当您重新定位Node(实际矩形)时,方法relocate()只需设置translateX和translateY值,并且该转换也应用于Group的布局边界。要解决此问题,您可以将组更改为AnchorPane。

    1. 调整矩形大小的方法不正确。您需要在第一次单击事件发生时获取第一个鼠标单击坐标,然后在拖动事件中获取新坐标,计算X和Y的delta值,并将该值添加到矩形的宽度和高度最后在drag事件监听器上更新firstX和firstY变量:

      deltaX = event.getX() - firstX;
      deltaY = event.getY() - firstY;
      
      customRectangle.setWidth(customRectangle.getWidth + deltaX);
      customRectangle.setHeight(customRectangle.getHeight + deltaY);
      
    2. 以上是上述示例:

      import javafx.application.Application;
      import javafx.event.EventHandler;
      import javafx.scene.Scene;
      import javafx.scene.input.MouseEvent;
      import javafx.scene.layout.AnchorPane;
      import javafx.scene.layout.BorderPane;
      import javafx.scene.layout.HBox;
      import javafx.scene.paint.Color;
      import javafx.scene.shape.Rectangle;
      import javafx.stage.Stage;
      
      public class Main extends Application {
          public static String shapeType = "";
          public static String color = "";
      
          private static Rectangle customRectangle = null;
      
          private double firstX = 0;
          private double firstY = 0;
      
          public void start(Stage mainStage) throws Exception {
      
              BorderPane mainPane = new BorderPane();
      
              HBox centerPane = new HBox();
      
              centerPane.prefWidthProperty().bind(mainPane.widthProperty());
              centerPane.prefHeightProperty().bind(mainPane.heightProperty());
      
              AnchorPane anchorPane = new AnchorPane();
      
              anchorPane.prefWidthProperty().bind(centerPane.widthProperty());
              anchorPane.prefHeightProperty().bind(centerPane.heightProperty());
      
              centerPane.getChildren().add(anchorPane);
      
              centerPane.setStyle("-fx-background-color: yellow");
      
              shapeType = "rectangle";
      
              mainPane.setCenter(centerPane);
      
              centerPane.addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
                  @Override
                  public void handle(MouseEvent event) {
      
                      if (event.getEventType() == MouseEvent.MOUSE_PRESSED && shapeType != "") {
                          switch (shapeType) {
                          case "rectangle":
                              firstX = event.getX();
                              firstY = event.getY();
                              createCustomRectangle(event, color, anchorPane);
                          }
                      }
                      if (event.getEventType() == MouseEvent.MOUSE_DRAGGED) {
                          switch (shapeType) {
                          case "rectangle":
                              editCustomRectangle(event);
                              firstX = event.getX();
                              firstY = event.getY();
                          }
                      }
                  }
              });
      
              Scene scene = new Scene(mainPane, 600, 400);
              mainStage.setScene(scene);
              mainStage.show();
          }
      
          public void createCustomRectangle(MouseEvent event, String color, AnchorPane canvasGroup) {
              customRectangle = new Rectangle(0, 0, 10, 10); // or just set the actual X and Y from the start
              customRectangle.relocate(event.getX(), event.getY());
      
              customRectangle.setFill(Color.RED);
              canvasGroup.getChildren().add(customRectangle);
          }
      
          public void editCustomRectangle(MouseEvent event) {
      
              double deltaX = event.getX() - firstX;
              double deltaY = event.getY() - firstY;
      
              double width = customRectangle.getWidth() + deltaX;
              double height = customRectangle.getHeight() + deltaY;
      
              customRectangle.setWidth(width);
              customRectangle.setHeight(height);
          }
      
          public static void main(String[] args) {
              launch(args);
          }
      }
      

答案 1 :(得分:0)

嗯,首先,customRectangle.relocate(event.getX(), event.getY());显然没有做它应该做的事情。最好先在适当的位置创建矩形。

而不是:

customRectangle = new Rectangle(0, 0, 10,10);
customRectangle.relocate(event.getX(), event.getY());

尝试:
customRectangle = new Rectangle(event.getX(), event.getY(), 10,10);

其次,看起来customRectangle.getTranslateX()customRectangle.getTranslateY()总是返回0,所以我要看看这些方法,看看那里发生了什么。祝你好运,希望这有帮助。

编辑: 而不是relocate可以尝试使用setTranslateX()setTranslateY()

答案 2 :(得分:0)

感谢大家的建议!我发现我认为对我的问题最直接的解决方案。其中很大一部分是Group不是那种允许我采取行动的节点。它将每个新添加的节点/对象附加到先前创建的节点/对象的右侧。所以,我切换到StackPane并获得了更好的结果。问题在于它在StackPane的中心创建了所有内容。我的解决方案是设置形状的对齐方式。很大程度上,其他一切都保持不变。

以下是任何想要执行类似操作的人的相关代码段(我的原始帖子有更完整的代码):

StackPane stackCanvas = new StackPane();

stackCanvas.setStyle("-fx-background-color: yellow");

borderPane.setTop(shapeOptions);
borderPane.setLeft(colorOptions);
borderPane.setCenter(stackCanvas);

public static void createCustomRectangle(MouseEvent event, String color, StackPane stackCanvas){
    customRectangle = new Rectangle();
    StackPane.setAlignment(customRectangle, Pos.TOP_LEFT);
    stackCanvas.getChildren().add(customRectangle);

    customRectangle.setTranslateX(event.getX());
    customRectangle.setTranslateY(event.getY());

    customRectangle.setFill(Color.RED);
}