背景
引入于处理3是一种 JavaFX 渲染模式,可以将 JavaFX 包含在我们的草图中。我们可以不从头开始创建自己的 JavaFX 窗口,然后将草图嵌入其中,修改由PApplet类构造的窗口当它在 JavaFX 模式下初始化时,在其中添加新的 JavaFX 元素。
在 JavaFX 模式下初始化期间,PApplet 类创建一个javafx.scene.canvas.Canvas
对象并将其作为子对象添加到javafx.scene.layout.StackPane
目的。然后,一个javafx.scene.Scene
对象是用堆栈窗格对象作为参数。最后,PApplet 类创建一个javafx.stage.Stage
对象并将其场景设置为scene对象,为我们提供 PApplet 实例 - 草图。
因此,就 JavaFX 元素而言,PApplet 窗口由以下层次结构中的四个元素初始化:Stage > Scene > StackPane > Canvas
,其中canvas是草图的图形画布(即处理绘制的对象)。
创建我们自己的 GUI,我们可以添加任何javafx.scene.Node
对象(这是 JavaFX 图形元素的超类)到堆栈窗格目的。或者你可以构建一个新的Scene,将Processing的画布添加到其中,并替换现有的Scene of the Stage.
什么似乎不起作用
如果不指定渲染模式,Processing默认为JAVA2D
模式。在此模式下,PApplet 类创建一个 PApplet 实例java.awt
画布和窗口的版本(ajava.awt.Canvas
and java.awt.Frame
分别)。理论上来说,可以投java.awt.Frame
to a javax.swing.JFrame
,将其嵌入到javafx.embed.swing.SwingNode
对象,最后将其添加到 JavaFX 阶段。但是,我无法让它发挥作用。
还有P2D
& P3D
模式。在这些模式下,画布是com.jogamp.newt.opengl.GLWindow
目的。再次,我尝试在 Swing Node 的帮助下将其嵌入com.jogamp.opengl.awt.GLJPanel
,但尚未证明是成功的。
执行
在处理中初始化你的草图FX2D
调用中的渲染模式size()
:
size([width], [height], FX2D);
然后,我们可以通过重复转换公开初始化期间创建的四个 JavaFX 元素:
final PSurfaceFX FXSurface = (PSurfaceFX) surface;
final Canvas canvas = (Canvas) FXSurface.getNative();
final StackPane stackPane = (StackPane) canvas.getParent();
final Scene scene = canvas.getScene();
final Stage stage = (Stage) canvas.getScene().getWindow();
我们现在可以选择如何添加 JavaFX 元素:
1)添加到现有的stackPane
我们可以添加 JavaFX 元素(javafx.scene.Node
对象)到堆栈窗格它是在初始化期间使用以下方法创建的:
stackPane.getChildren().add(Node node);
2)创建新场景(推荐)
或者(推荐,除非您想要 stackPane 作为顶级对齐器),我们可以创建一个新的场景对象(而不是使用scene and 堆栈窗格初始化期间创建的对象)并向其中添加 JavaFX 元素。
Scene newscene = new Scene(new Group(canvas)); // simple group containing only the Processing canvas
stage.setScene(Scene scene);
在初始化期间,canvas' 尺寸绑定到堆栈窗格。如果我们希望在运行时更改窗口内处理画布的大小,则必须包括以下内容:
canvas.widthProperty().unbind();
canvas.heightProperty().unbind();
现在我们可以自由调用canvas.setHeight()
and canvas.setWidth()
调整 JavaFX 窗口(舞台)内的处理画布的大小。
Example
让我们添加一个javafx.scene.control.MenuBar
到窗户。请注意,我正在初始化 JavaFX 元素initSurface()
方法而不是在setup()
方法,因为这样比较安全。
在此示例中,堆栈窗格被替换为javafx.scene.layout.VBox
,首先,使菜单栏位于canvas第二,确保stage是启动时的正确高度(菜单栏高度和画布高度的总和)。
@Override
public void settings() {
size(500, 500, FX2D);
}
@Override
protected PSurface initSurface() {
PSurface surface = super.initSurface();
final PSurfaceFX FXSurface = (PSurfaceFX) surface;
final Canvas canvas = (Canvas) FXSurface.getNative(); // canvas is the processing drawing
final Stage stage = (Stage) canvas.getScene().getWindow(); // stage is the window
stage.setTitle("Processing/JavaFX Example");
canvas.widthProperty().unbind();
canvas.heightProperty().unbind();
final MenuItem menuItem1 = new MenuItem("Fill green");
menuItem1.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
noLoop();
background(0, 255, 0); // Fills the canvas green on click
}
});
final MenuItem menuItem2 = new MenuItem("Exit");
menuItem2.setOnAction(actionEvent -> exit()); // Exit PApplet on click
final Menu menu = new Menu("Menu");
menu.getItems().add(menuItem1);
menu.getItems().add(menuItem2);
final MenuBar menuBar = new MenuBar();
menuBar.getMenus().add(menu);
final VBox vBox = new VBox(menuBar, canvas); // Menubar will sit on top of canvas
final Scene newscene = new Scene(vBox); // Create a scene from the elements
Platform.runLater(new Runnable() {
@Override
public void run() {
stage.setScene(newscene); // Replace the stage's scene with our new one.
}
});
return surface;
}
@Override
public void draw() {
background(50);
fill(0, 255, 0);
strokeWeight(5);
stroke(255, 5, 5);
line(0, 0, width, 0); // shows us that window is the correct dimensions
line(0, height, width, height); // shows us that window is the correct dimensions
noStroke();
ellipse(100, 100, 200, 200);
fill(255, 0, 0);
ellipse(100, 200, 200, 200);
fill(0, 0, 255);
ellipse(100, 300, 200, 200);
}
Result