如何在javafx中嵌入PApplet? [英] How to embed a PApplet in javafx?

查看:276
本文介绍了如何在javafx中嵌入PApplet?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

So I got my Processing code working in java. But now I want to embed it in JavaFX for my GUI. How can I do so? I tried using the following code but it does not seem to work.

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

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

I get error at getRootPane(). Can you suggest an alternative for it?

推荐答案

背景



介绍在 Processing 3 中是一种JavaFX渲染模式,可以在我们的草图中包含JavaFX。不是从头创建我们自己的JavaFX窗口,然后在其中嵌入我们的草图,我们可以修改由PApplet类构建的窗口,当它在JavaFX模式下初始化时,在其中添加新的JavaFX元素。

Background

Introduced in Processing 3 was a JavaFX rendering mode that makes it possible to include JavaFX in our sketches. Rather than creating our own JavaFX window from scratch and then embedding our sketch within it, we can modify the window that is constructed by the PApplet class when it is initialised in JavaFX mode, adding new JavaFX elements therein.

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

During initialisation in JavaFX mode, the PApplet class creates a javafx.scene.canvas.Canvas object and adds this as a child to a javafx.scene.layout.StackPane object. Then, a javafx.scene.Scene object is constructed with the stackPane object as a parameter. Finally, the PApplet class creates a javafx.stage.Stage object and sets its scene to the scene object, to give us our PApplet instance - the sketch.

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

So in terms of JavaFX elements, the PApplet window is initialised with four elements in the following hierarchy: Stage > Scene > StackPane > Canvas, where the canvas is the graphical canvas of the sketch (ie. the object that Processing draws to).

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

To create our own GUI, we can add any javafx.scene.Node object (this is the superclass of JavaFX graphical elements) to the stackPane object. Alternatively you could construct a new Scene, add the Processing's canvas to it, and replace the existing Scene of the Stage.

未指定渲染模式,处理默认为 JAVA2D 模式。在此模式下,PApplet类使用 java.awt 版本的画布和窗口创建一个PApplet实例( java.awt.Canvas java.awt.Frame 。从理论上讲,可以将 java.awt.Frame 转换为 javax.swing.JFrame ,嵌入此在 javafx.embed.swing.SwingNode 对象中,最后将其添加到JavaFX阶段。但是,我无法让它工作。

Without specifying the rendering mode, Processing defaults to JAVA2D mode. In this mode, the PApplet class creates a PApplet instance with java.awt versions of the canvas and window (a java.awt.Canvas and java.awt.Frame respectively). In theory, it is possible to cast the java.awt.Frame to a javax.swing.JFrame, embed this in a javafx.embed.swing.SwingNode object and finally add this to a JavaFX stage. However, I haven't been able to get this to work.

还有 P2D & P3D 模式。在这些模式中,画布是 com.jogamp.newt.opengl.GLWindow 对象。同样,我试图在一个 com.jogamp.opengl.awt.GLJPanel 的帮助下将其嵌入到Swing节点中,但是它没有被证明是成功的。

There are also the P2D & P3D modes. In these modes, the canvas is a com.jogamp.newt.opengl.GLWindow object. Again, I have tried to embed this in a Swing Node, with the help of a com.jogamp.opengl.awt.GLJPanel, but it has not proven successful.

在Processing的 FX2D 调用尺寸的渲染模式()

Initialise your sketch in Processing's FX2D rendering mode in the call to size():

尺寸([宽度],[高度], FX2D );

size([width], [height], FX2D);

然后我们可以公开通过重复投射在初始化期间创建的四个JavaFX元素:

We can then expose the four JavaFX elements that were created during initialisation by repeated casting:

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元素:

We now have an option as to how we add our JavaFX elements:

1)添加到现有的stackPane

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

We can add JavaFX elements (javafx.scene.Node objects) to the stackPane that was created during initialisation with the following method:

stackPane.getChildren().add(Node node);

2)创建一个新场景(推荐)

或者(建议,除非你想将stackPane作为顶级对齐器),我们可以创建一个新的场景对象(而不是使用场景初始化期间创建的> stackPane 对象,并将JavaFX元素添加到此。

Alternatively (recommended, unless you want a stackPane as a top-level aligner), we can create a new scene object (rather than using the scene and stackPane objects that were created during initialisation) and add JavaFX elements to this.

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

在初始化过程中, canvas '维度与 stackPane 。如果我们希望在运行时在窗口内更改Processing画布的大小,我们必须包含以下内容:

During initialisation, the canvas' dimensions are binded to those of the stackPane. If we wish to change the size of the Processing canvas within the window during runtime, we must include the following:

canvas.widthProperty().unbind();
canvas.heightProperty().unbind();

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

Now we can freely call canvas.setHeight() and canvas.setWidth() to resize to Processing canvas within the JavaFX window (the stage).

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

Let's add a javafx.scene.control.MenuBar to the window. Note that I am initialising our JavaFX elements within the initSurface() method rather than doing so within the setup() method, as it's safer.

在此示例中, stackPane 替换为 javafx.scene.layout.VBox ,首先,让菜单栏位于 canvas 的顶部,其次,确保 stage 是正确的高度(menuBar高度和画布高度的总和)在发布时。

In this example, the stackPane is replaced with a javafx.scene.layout.VBox, first, so that the menubar sits atop of the canvas and second, to ensure the stage is the correct height (the sum of the menuBar height and canvas height) at launch.

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

结果

这篇关于如何在javafx中嵌入PApplet?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆