我正在尝试创建一个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
希望描述,代码和图像足以传达正在发生的事情。任何帮助将不胜感激。
谢谢!
答案 0 :(得分:2)
让我们一次开始解决每个问题。首先是一个友好的建议,尝试以一种帮助读者理解其含义和身份的方式命名变量(当我第一次看到canvas变量时,我认为它是一个真正的Canvas)。
现在您的布局是这样的:
BorderPane
TOP
- Something
CENTER
- HBox
- Group
- Rectangle
- Rectangle
- ...
Left
- Something
Bottom
- Something
HBox取得所有可用的高度,并根据其子项计算宽度。所以为了拿走所有的 您需要实际指定BorderPane中的可用空间或将其preferredWidthProperty绑定到 BorderPane的widthProperty。
从Group类的文档中可以看到:
应用于组的任何转换,效果或状态都将应用于 该群体的所有孩子。这样的变换和效果不会 但是,如果转换和包含在此组的布局范围内 效果直接设定在本集团的子女身上 包含在本集团的布局范围内。
因此,当您重新定位Node(实际矩形)时,方法relocate()只需设置translateX和translateY值,并且该转换也应用于Group的布局边界。要解决此问题,您可以将组更改为AnchorPane。
调整矩形大小的方法不正确。您需要在第一次单击事件发生时获取第一个鼠标单击坐标,然后在拖动事件中获取新坐标,计算X和Y的delta值,并将该值添加到矩形的宽度和高度最后在drag事件监听器上更新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);
}
}
答案 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);
}