如何在javafx中嵌入PApplet?

sj6*_*j66 3 java processing user-interface netbeans javafx

所以我让我的处理代码在java中运行。但现在我想将它嵌入到我的 GUI 的 JavaFX 中。我怎样才能这样做呢?我尝试使用以下代码,但它似乎不起作用。

 package testprocessing;
import javafx.application.Application;
import javafx.embed.swing.SwingNode;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import javax.swing.JApplet;
import javax.swing.SwingUtilities;
import java.awt.Dimension;

import java.util.concurrent.*;
import processing.core.*;

public class JavaFxApplet extends Application {
    private PApplet applet = new MyProcessingSketch();
    private Dimension appletSize;

    @Override public void init() throws ExecutionException, InterruptedException {
        applet.init();

        FutureTask<Dimension> sizingTask = new FutureTask<>(() ->
            applet.getRootPane().getPreferredSize()
        );
        SwingUtilities.invokeLater(sizingTask);
        appletSize = sizingTask.get();
    }

    @Override public void start(Stage stage) {
        final SwingNode swingNode = new SwingNode();
        SwingUtilities.invokeLater(() ->
            swingNode.setContent(applet.getRootPane())
        );

        stage.setScene(
            new Scene(
                new Group(swingNode),
                appletSize.getWidth(), appletSize.getHeight(),
                Color.BLACK
            )
        );
        stage.show();
    }

    @Override public void stop() {
        applet.stop();
        applet.destroy();
    }

    public static void main(String[] args) {
         launch(args);
     }
}
Run Code Online (Sandbox Code Playgroud)

我在 getRootPane() 处收到错误。你能建议一个替代方案吗?

mic*_*cle 5

背景

Process 3中引入了 JavaFX 渲染模式,可以将 JavaFX 包含在我们的草图中。我们可以修改 PApplet 类在 JavaFX 模式下初始化时构造的窗口,在其中添加新的 JavaFX 元素,而不是从头开始创建我们自己的 JavaFX 窗口,然后将草图嵌入其中。

在 JavaFX 模式下初始化期间,PApplet 类创建一个javafx.scene.canvas.Canvas对象并将其作为子对象添加到javafx.scene.layout.StackPane对象中。然后,以stackPane对象作为参数javafx.scene.Scene构造一个对象。最后,PApplet 类创建一个对象并将其场景设置为场景对象,为我们提供 PApplet 实例 - 草图。javafx.stage.Stage

因此,就 JavaFX 元素而言,PApplet 窗口使用以下层次结构中的四个元素进行初始化:Stage > Scene > StackPane > Canvas,其中画布是草图的图形画布(即,Processing 绘制到的对象)。

要创建我们自己的 GUI,我们可以将任何javafx.scene.Node对象(这是 JavaFX 图形元素的超类)添加到stackPane对象。或者,您可以构造一个新的Scene,向其中添加处理的画布,然后替换Stage的现有Scene


什么似乎不起作用

如果不指定渲染模式,Processing默认为JAVA2Dmode。在此模式下,PApplet 类创建一个带有java.awt画布和窗口版本(分别为 ajava.awt.Canvasjava.awt.Frame)的 PApplet 实例。理论上,可以将 转换java.awt.Frame为 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();
Run Code Online (Sandbox Code Playgroud)

我们现在可以选择如何添加 JavaFX 元素:

1)添加到现有的stackPane

我们可以使用以下方法将 JavaFX 元素(javafx.scene.Node对象)添加到初始化期间创建的stackPane中:

stackPane.getChildren().add(Node node);
Run Code Online (Sandbox Code Playgroud)

2)创建新场景(推荐)

或者(推荐,除非您想要 stackPane 作为顶级对齐器),我们可以创建一个新的场景对象(而不是使用初始化期间创建的场景stackPane对象)并向其中添加 JavaFX 元素。

Scene newscene = new Scene(new Group(canvas)); // simple group containing only the Processing canvas
stage.setScene(Scene scene);
Run Code Online (Sandbox Code Playgroud)

在初始化期间,画布的尺寸绑定到stackPane的尺寸。如果我们希望在运行时更改窗口内处理画布的大小,则必须包括以下内容:

canvas.widthProperty().unbind();
canvas.heightProperty().unbind();
Run Code Online (Sandbox Code Playgroud)

现在我们可以在 JavaFX 窗口(舞台)内自由调用canvas.setHeight()和调整处理画布的大小。canvas.setWidth()

例子

让我们javafx.scene.control.MenuBar向窗口添加一个。请注意,我是在方法内初始化 JavaFX 元素,initSurface()而不是在方法内初始化setup(),因为这样更安全。

在此示例中,stackPane被替换为javafx.scene.layout.VBox,首先,以便菜单栏位于画布顶部,其次,确保舞台在启动时具有正确的高度(菜单栏高度和画布高度的总和)。

@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);
}
Run Code Online (Sandbox Code Playgroud)

结果

结果