使用 Javafx 中的 ui 组件为图形编辑器创建自定义形状
Create custom shape with ui components in Javafx for graph editor
我正在做一个个人图形编辑器项目,我想为自动代码生成创建类似流程图的图形。我的第一个想法是 Canvas
和 GraphicsContext
,但结果太复杂了,因为我必须手动绘制所有内容。所以我切换到 Shape
.
基本上,每个节点都是一个Shape
,上面有其他标准ui组件,例如Label
、ChoiceBox
等。由于每个节点代表一个程序功能,我想使用这些 ui 组件来选择函数的输入。
我正在用 StackPane
做一些实验,一个 Rectangle
在背景中,上面有一些 Label
:
public class RectangleNode extends StackPane {
private double x;
private double y;
private VBox vbox;
private Rectangle rect;
public RectangleNode(double x, double y) {
super();
setAlignment(Pos.CENTER);
this.x = x;
this.y = y;
Label label1 = new Label("Hello world");
Label label2 = new Label("Hello JavaFX");
vbox = new VBox(label1, label2);
rect = new Rectangle();
rect.setStroke(Color.ALICEBLUE);
rect.setStrokeWidth(2);
rect.setX(this.x);
rect.setY(this.y);
getChildren().addAll(rect, vbox);
}
public void updateSize () {
double width = vbox.getLayoutBounds().getWidth();
double height = vbox.getLayoutBounds().getHeight();
System.out.println("width vbox: " + width + "px");
System.out.println("height vbox: " + height + "px");
rect.setWidth(width + 10);
rect.setHeight(height + 10);
}
}
节点放置在 Pane
内,因为它提供组件的绝对定位:
public class StackPaneTest extends Application {
public void start(Stage stage) throws Exception {
Pane root = new Pane();
stage.setTitle("StackPane Test");
stage.setScene(new Scene(root, 480, 360));
stage.show();
RectangleNode pane = new RectangleNode(100, 100);
root.getChildren().add(pane);
pane.updateSize();
}
public static void main(String[] args) {
launch(args);
}
}
然后我发现这里有几个问题:
getLayoutBounds().getWidth()
和getLayoutBounds().getHeight()
总是return零,所以我不能根据标签的大小调整矩形的大小,我怎么能获取 vbox
? 的实际大小
- 即使我用
setX
和 setY
设置了 Rectangle
的坐标,StackPane
总是在 Pane
的左上角,我怎样才能绝对定位它?
StackPane
是正确的方法吗?
谢谢。
the getLayoutBounds().getWidth() and getLayoutBounds().getHeight()
always return zero, so I cannot resize the rectangle according the
size of labels, how can I get the real size of vbox?
在场景图中渲染边界之前,您正在检查边界。如果你用 Platform.runLater
包装你的方法调用,你可以获得正确的值
Platform.runLater(()->pane.updateSize());
不过,我建议摆脱 updateSize() 方法并将矩形边界与 RectanglePane 边界绑定,这样您就不必担心基础形状的边界更新。
rect.widthProperty().bind(widthProperty());
rect.heightProperty().bind(heightProperty());
The StackPane is always in the top-left corer of Pane even I have set
the coordinates of Rectangle with setX and setY, how can I position it
absolutely?
您正在更新矩形属性,这是不正确的。相反,您必须实际更新 StackPane translateX/Y 属性才能移动您的 RectanglePane。将构造函数中的代码更新为以下内容。
//rect.setX(this.x);
//rect.setY(this.y);
setTranslateX(this.x);
setTranslateY(this.y);
Is StackPane the right approach?
据我了解您的要求,如果您正在寻找一种布局以在下方放置一个 Shape 并将您的自定义布局置于其上方,我认为 StackPane 是一个不错的选择。
您还可以进行其他较小的更改。以下是更新后的演示,仅供参考。
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class StackPaneTest extends Application {
public void start(Stage stage) throws Exception {
Pane root = new Pane();
stage.setTitle("StackPane Test");
stage.setScene(new Scene(root, 480, 360));
stage.show();
root.getChildren().add(new RectangleNode(100, 100));
}
public static void main(String[] args) {
launch(args);
}
}
class RectangleNode extends Group {
private VBox vbox;
private Rectangle rect;
public RectangleNode(double x, double y) {
super();
StackPane layout = new StackPane();
layout.setAlignment(Pos.TOP_LEFT);
Label label1 = new Label("Hello world");
Label label2 = new Label("Hello JavaFX");
vbox = new VBox(label1, label2);
vbox.setPadding(new Insets(5));
setTranslateX(x);
setTranslateY(y);
rect = new Rectangle();
rect.setFill(Color.YELLOW);
rect.setStrokeWidth(2);
rect.setStroke(Color.BLACK);
rect.widthProperty().bind(layout.widthProperty());
rect.heightProperty().bind(layout.heightProperty());
layout.getChildren().addAll(rect, vbox);
getChildren().add(layout);
}
}
我正在做一个个人图形编辑器项目,我想为自动代码生成创建类似流程图的图形。我的第一个想法是 Canvas
和 GraphicsContext
,但结果太复杂了,因为我必须手动绘制所有内容。所以我切换到 Shape
.
基本上,每个节点都是一个Shape
,上面有其他标准ui组件,例如Label
、ChoiceBox
等。由于每个节点代表一个程序功能,我想使用这些 ui 组件来选择函数的输入。
我正在用 StackPane
做一些实验,一个 Rectangle
在背景中,上面有一些 Label
:
public class RectangleNode extends StackPane {
private double x;
private double y;
private VBox vbox;
private Rectangle rect;
public RectangleNode(double x, double y) {
super();
setAlignment(Pos.CENTER);
this.x = x;
this.y = y;
Label label1 = new Label("Hello world");
Label label2 = new Label("Hello JavaFX");
vbox = new VBox(label1, label2);
rect = new Rectangle();
rect.setStroke(Color.ALICEBLUE);
rect.setStrokeWidth(2);
rect.setX(this.x);
rect.setY(this.y);
getChildren().addAll(rect, vbox);
}
public void updateSize () {
double width = vbox.getLayoutBounds().getWidth();
double height = vbox.getLayoutBounds().getHeight();
System.out.println("width vbox: " + width + "px");
System.out.println("height vbox: " + height + "px");
rect.setWidth(width + 10);
rect.setHeight(height + 10);
}
}
节点放置在 Pane
内,因为它提供组件的绝对定位:
public class StackPaneTest extends Application {
public void start(Stage stage) throws Exception {
Pane root = new Pane();
stage.setTitle("StackPane Test");
stage.setScene(new Scene(root, 480, 360));
stage.show();
RectangleNode pane = new RectangleNode(100, 100);
root.getChildren().add(pane);
pane.updateSize();
}
public static void main(String[] args) {
launch(args);
}
}
然后我发现这里有几个问题:
getLayoutBounds().getWidth()
和getLayoutBounds().getHeight()
总是return零,所以我不能根据标签的大小调整矩形的大小,我怎么能获取vbox
? 的实际大小
- 即使我用
setX
和setY
设置了Rectangle
的坐标,StackPane
总是在Pane
的左上角,我怎样才能绝对定位它? StackPane
是正确的方法吗?
谢谢。
the getLayoutBounds().getWidth() and getLayoutBounds().getHeight() always return zero, so I cannot resize the rectangle according the size of labels, how can I get the real size of vbox?
在场景图中渲染边界之前,您正在检查边界。如果你用 Platform.runLater
包装你的方法调用,你可以获得正确的值Platform.runLater(()->pane.updateSize());
不过,我建议摆脱 updateSize() 方法并将矩形边界与 RectanglePane 边界绑定,这样您就不必担心基础形状的边界更新。
rect.widthProperty().bind(widthProperty());
rect.heightProperty().bind(heightProperty());
The StackPane is always in the top-left corer of Pane even I have set the coordinates of Rectangle with setX and setY, how can I position it absolutely?
您正在更新矩形属性,这是不正确的。相反,您必须实际更新 StackPane translateX/Y 属性才能移动您的 RectanglePane。将构造函数中的代码更新为以下内容。
//rect.setX(this.x);
//rect.setY(this.y);
setTranslateX(this.x);
setTranslateY(this.y);
Is StackPane the right approach?
据我了解您的要求,如果您正在寻找一种布局以在下方放置一个 Shape 并将您的自定义布局置于其上方,我认为 StackPane 是一个不错的选择。
您还可以进行其他较小的更改。以下是更新后的演示,仅供参考。
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class StackPaneTest extends Application {
public void start(Stage stage) throws Exception {
Pane root = new Pane();
stage.setTitle("StackPane Test");
stage.setScene(new Scene(root, 480, 360));
stage.show();
root.getChildren().add(new RectangleNode(100, 100));
}
public static void main(String[] args) {
launch(args);
}
}
class RectangleNode extends Group {
private VBox vbox;
private Rectangle rect;
public RectangleNode(double x, double y) {
super();
StackPane layout = new StackPane();
layout.setAlignment(Pos.TOP_LEFT);
Label label1 = new Label("Hello world");
Label label2 = new Label("Hello JavaFX");
vbox = new VBox(label1, label2);
vbox.setPadding(new Insets(5));
setTranslateX(x);
setTranslateY(y);
rect = new Rectangle();
rect.setFill(Color.YELLOW);
rect.setStrokeWidth(2);
rect.setStroke(Color.BLACK);
rect.widthProperty().bind(layout.widthProperty());
rect.heightProperty().bind(layout.heightProperty());
layout.getChildren().addAll(rect, vbox);
getChildren().add(layout);
}
}