所以我的处理代码在java中运行。但现在我想将它嵌入JavaFX中以用于我的GUI。我怎么能这样做? 我尝试使用以下代码,但它似乎不起作用。
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()时遇到错误。你能为它建议一个替代方案吗?
答案 0 :(得分:1)
处理3 中引入的是JavaFX渲染模式,该模式可以将JavaFX包括在草图中。不必从头创建我们自己的JavaFX窗口,然后将其嵌入其中,我们可以在JavaFX模式下初始化时,修改由PApplet类构造的窗口,在其中添加新的JavaFX元素。
在JavaFX模式下初始化期间,PApplet类创建一个javafx.scene.canvas.Canvas
对象,并将其作为子对象添加到javafx.scene.layout.StackPane
对象中。然后,使用 stackPane 对象作为参数构造一个javafx.scene.Scene
对象。最后,PApplet类创建一个javafx.stage.Stage
对象,并将其场景设置为 scene 对象,以提供我们的PApplet实例-草图。
因此,就JavaFX元素而言,PApplet窗口由以下层次结构中的四个元素初始化:Stage > Scene > StackPane > Canvas
,其中 canvas 是草图的图形画布(即处理绘制到的对象)。
要创建自己的GUI ,我们可以将任何javafx.scene.Node
对象(这是JavaFX图形元素的超类)添加到 stackPane 对象。或者,您可以构造一个新的 Scene ,向其中添加Processing的画布,并替换 Stage 中现有的 Scene 。
在未指定渲染模式的情况下,“处理”默认为JAVA2D
模式。在这种模式下,PApplet类使用画布和窗口的java.awt
版本(分别为java.awt.Canvas
和java.awt.Frame
)创建一个PApplet实例。从理论上讲,可以将java.awt.Frame
转换为javax.swing.JFrame
,将其嵌入到javafx.embed.swing.SwingNode
对象中,最后将其添加到JavaFX阶段。但是,我无法使它正常工作。
还有P2D
和P3D
模式。在这些模式下,画布是com.jogamp.newt.opengl.GLWindow
对象。再次,我尝试在com.jogamp.opengl.awt.GLJPanel
的帮助下将其嵌入到Swing节点中,但是事实证明它没有成功。
在对FX2D
的调用中,以Processing的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 中:
stackPane.getChildren().add(Node node);
2)创建一个新场景(推荐)
(推荐,除非您希望将stackPane用作顶层对齐器),我们可以创建一个新的场景对象(而不是使用 scene 和 stackPane 对象)在初始化过程中创建的),并向其中添加JavaFX元素。
Scene newscene = new Scene(new Group(canvas)); // simple group containing only the Processing canvas
stage.setScene(Scene scene);
在初始化期间, canvas 的尺寸绑定到 stackPane 的尺寸。如果我们希望在运行时更改窗口内“处理”画布的大小,则必须包括以下内容:
canvas.widthProperty().unbind();
canvas.heightProperty().unbind();
现在,我们可以在JavaFX窗口(阶段)中自由调用canvas.setHeight()
和canvas.setWidth()
来调整“正在处理”画布的大小。
让我们在窗口中添加一个javafx.scene.control.MenuBar
。请注意,我这样做是在initSurface()
方法中初始化JavaFX元素,而不是在setup()
方法中初始化JavaFX元素,因为这样做更安全。
在此示例中,首先用javafx.scene.layout.VBox
替换 stackPane ,使菜单栏位于 canvas 的顶部,其次是确保菜单栏位于 stage 是启动时的正确高度(menuBar高度和画布高度的总和)。
@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);
}
结果
答案 1 :(得分:0)
为什么要尝试获取applet的根窗格?只需将applet添加到JPanel,然后将JPanel添加到SwingNode:
JPanel panel = new JPanel();
panel.add(applet);
swingNode.setContent(panel)