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



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

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

目前,我创建的第一个形状放置在 BorderPane 中心部分中 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);
}
}

我还想附上几张图片,让我的问题更清楚。下面尝试创建第一个形状: 单击并拖动以创建第一个形状

这里正在尝试创建一个后续形状: 单击并拖动以创建另一个形状

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

谢谢!

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

现在你的布局是这样的:

BorderPane 
TOP 
- Something
CENTER 
- HBox
- Group
- Rectangle
- Rectangle
- ...
Left
- Something
Bottom 
- Something
  1. HBox 采用所有可用高度并根据其子级计算其宽度。所以为了拿走所有的 边框窗格中的可用空间需要实际指定它或将其首选宽度属性与 宽度边框窗格的属性。

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

应用于

组的任何变换、效果或状态都将应用于 该组的所有儿童。这样的转换和效果不会 但是,包含在此组的布局边界中,如果转换和 效果直接设置在本组的孩子身上,这些将是 包含在此组的布局边界中。

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

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

    deltaX = event.getX() - firstX;
    deltaY = event.getY() - firstY;
    customRectangle.setWidth(customRectangle.getWidth + deltaX);
    customRectangle.setHeight(customRectangle.getHeight + deltaY);
    

这是上述示例:

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);
}
}

首先,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().

感谢大家的建议! 我找到了我认为最直接的问题解决方案。 很大一部分是该组不是允许我采取预期行动的节点。 它将每个新添加的节点/对象附加到先前创建的节点/对象的右侧。因此,我切换到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);
}

最新更新