# JavaFX Controls in Default Window

**URL:** <https://discourse.processing.org/t/javafx-controls-in-default-window/46404>\
**Category:** Development\
**Created:** [May 17, 2025, 2:09pm UTC](https://discourse.processing.org/t/javafx-controls-in-default-window/46404 "2025-05-17T14:09:49Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [May 17, 2025, 2:09pm UTC](https://discourse.processing.org/t/javafx-controls-in-default-window/46404/1 "2025-05-17T14:09:49Z")

</div>

Is there anyone in this forum who can retrieve the root pane of a PSurfaceFX window?

Currently it is not possible to place javafx controls in a default Processing window using JavaMode. It has recently been shown by @hx2A that this is possible in Py5 but requires getting the layout pane for PSurfaceFX which he found a way to do with _getParent()_:[py5 Sketch + JavaFX controls · py5coding/py5generator · Discussion #645 · GitHub](https://github.com/py5coding/py5generator/discussions/645). However, I am unable to do the same thing in JavaMode using the same or similar technique, eg getParent(), getRootPane(), or getContentPane(). I would like for anyone with an interest to see if they can retrieve the root layout pane from the PSurfaceFX window created for the FX2D renderer. If it can be retrieved then we should be able to proceed to place javafx controls in the default window. If it is found to not be possible then perhaps we can add a function to the runtime to retrieve the root as previously proposed and described here: [Using JavaFX in processing applet · Issue #4750 · processing/processing · GitHub](https://github.com/processing/processing/issues/4750).

StackPane was chosen as the default layout pane for PSurfaceFX and sets the origin to the center of the window. This alignment can be changed for individual controls if necessary but there are still limits to where controls can be positioned. There are several layout pane possibilities, each with their own characteristics: HBox, VBox, FlowPane, BorderPane, StackPane, TilePane, GridPane, AnchorPane, and TextFlow. In my opinion, it would make more sense to allow the user to select which layout pane they want to use, or alternatively use a regular Pane as shown in the example below and use setLayoutX()/setLayoutY() to place the control anywhere in the window.

There are two issues in my view, the first being the most important:

1. Add a function to return the root pane of the PSurfaceFX window, assuming that there is no way to currently do this in JavaMode.
2. Consider using a more generic pane which will allow control placement anywhere in the window as shown below, or alternatively making it possible for the user to select which layout pane is used.

**Current technique creating a separate javafx window for controls:**

```auto
// Uses a generic root pane and creates a separate javafx window with stage and scene

import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.layout.Pane;
import javafx.scene.control.Button;

void setup() {
  size(1, 1, FX2D);
  Stage stage = new Stage();
  stage.setTitle("JavaFX Controls");
  Pane pane = new Pane();
  Button btn = new Button("Push Me");
  btn.setLayoutX(150);
  btn.setLayoutY(100);
  pane.getChildren().add(btn);
  Scene scene = new Scene(pane, 400, 250);
  stage.setScene(scene);
  stage.show();
}

```

**Proposed new technique to place javafx controls directly in default Processing window:**

**PSEUDOCODE – WILL NOT RUN**

```auto
import javafx.scene.control.Button;

void setup() {
  size(400, 250, FX2D);
  canvas = surface.getNative();
  pane = canvas.getParent();
  Button btn = new Button("Push Me");
  btn.setLayoutX(150);
  btn.setLayoutY(100);
  pane.getChildren().add(btn);
}

```

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [May 17, 2025, 3:29pm UTC](https://discourse.processing.org/t/javafx-controls-in-default-window/46404/2 "2025-05-17T15:29:44Z")

</div>

I have this very old incomplete attempt I did a long time ago that handles all Processing renderers, including [FX2D](https://processing.github.io/processing-javadocs/core/processing/core/PConstants.html#FX2D) for Processing 3:

> [@Event called when canvas is resized](https://discourse.processing.org/t/event-called-when-canvas-is-resized/6643/8):
>
> Hi @Sarah! Here’s a sketch I’ve been working w/ many months ago. construction_worker_man It’s about creating a class callback which triggers every time the canvas resizes. robot It’s still experimental. man_scientist Yet to finish it 100% . But it’s runnable already: running_man

The most relevant parts of that code for JavaFX:

```auto
import processing.core.PApplet;
import processing.core.PGraphics;

```

```auto
// FX2D
import javafx.scene.canvas.Canvas;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;

```

```auto
protected final PApplet p;
protected final Object window;
protected final PGraphics pg;

```

```auto
public CanvasResizeWatcher(final PApplet pa, boolean now) {
  window = ( p = pa ).getSurface().getNative();
  pg = pa.getGraphics();

```

```auto
public String discoverRenderer() {
  if (window instanceof Canvas) return PApplet.FX2D;
  else if (pg.isGL()) return pg.is3D()? PApplet.P3D : PApplet.P2D;
  return PApplet.JAVA2D;
}

```

```auto
public interface SizeListener {
  SizeListener addListener();
  SizeListener removeListener();
}

```

```auto
protected SizeListener createRendererListener(String render) {
  if (render == null || render.isEmpty()) render = discoverRenderer();

  switch (render) {
  case PApplet.P2D:
  case PApplet.P3D:
    return new SizeListenerOPENGL();
  case PApplet.FX2D:
    return new SizeListenerFX2D<Double>();
  default:
    return new SizeListenerJAVA2D();
  }
}

```

```auto
public class SizeListenerFX2D<N extends Number>
  implements SizeListener, ChangeListener<N> {
  public final Canvas win = (Canvas) window;
  protected final ChangeListener changeListener = this;

  public SizeListenerFX2D() {
    if (listener != null) listener.removeListener();
    listener = addListener();
  }

  @Override public SizeListener addListener() {
    win.widthProperty().addListener(changeListener);
    win.heightProperty().addListener(changeListener);
    return this;
  }

  @Override public SizeListener removeListener() {
    win.widthProperty().removeListener(changeListener);
    win.heightProperty().removeListener(changeListener);
    return this;
  }

  @Override public void
    changed(ObservableValue<? extends N> obs, N old, N cur) {
    if (!immediate) resized.set(true);
    else invokeCallback();
  }

  @Override public String toString() {
    return discoverRenderer();
  }
}

```

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [May 18, 2025, 4:10pm UTC](https://discourse.processing.org/t/javafx-controls-in-default-window/46404/3 "2025-05-18T16:10:58Z")

</div>

Finally figured out how to get root pane of PSurfaceFX; the following works on my system (macOS). Note that control is in center of window because default layout pane is a StackPane and it defaults to CENTER alignment (can be changed by code).

**JavaFX control in default Processing window:**

```auto
import javafx.scene.canvas.Canvas;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;

Canvas canvas;
Pane pane;

void setup(){
  size(350,200,FX2D);
  surface.setTitle("JavaFX control in Default Wnd");
  canvas = (Canvas)surface.getNative();
  println(canvas);
  pane = (Pane)canvas.getParent();
  println(pane);
  Button btn = new Button("Push Me");
  pane.getChildren().add(btn);
}

```

**Output:**

 ![jfx_dw](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/0/5/051abbc0d58b6c9eb71ecbf07dd053b4dc0cca95.png)

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [May 18, 2025, 4:25pm UTC](https://discourse.processing.org/t/javafx-controls-in-default-window/46404/4 "2025-05-18T16:25:25Z")

</div>

> [@svan](#):
>
> `canvas = (javafx.scene.canvas.Canvas)surface.getNative();`

Given you’ve already imported class Canvas, you can shorten your (cast):  
`canvas = (Canvas)surface.getNative();`

Same for `pane = (javafx.scene.layout.Pane)canvas.getParent();`:  
`pane = (Pane)canvas.getParent();`

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [May 18, 2025, 7:03pm UTC](https://discourse.processing.org/t/javafx-controls-in-default-window/46404/5 "2025-05-18T19:03:12Z")

</div>

Thanks, I’ll edit it and make changes. Simplicity is good.

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [May 18, 2025, 7:13pm UTC](https://discourse.processing.org/t/javafx-controls-in-default-window/46404/6 "2025-05-18T19:13:34Z")

</div>

> [@svan](#):
>
> Finally figured out how to get root pane of PSurfaceFX; the following works on my system (macOS).

It appears to work with W10 as well on Processing 4.4.1.

Windows users interested in using JavaFX should read this first:

> [@Processing and JavaFX](https://discourse.processing.org/t/processing-and-javafx/45692/5):
>
> Hello folks! I can run JavaFX code examples (links below) with: Windows 10 Pro 22H2 Processing 4.3.2 Steps: Install the JavaFX library. Import the JavaFX library in your code: Add the JavaFX modules (jar files in modules folder) to your sketch folder. I have some code below to assist with finding them. The simplest way to do this is to drag and drop them into your sketch window. This will create a folder called code that contains them. Or… You cold also manual…

`:)`

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [May 20, 2025, 1:33pm UTC](https://discourse.processing.org/t/javafx-controls-in-default-window/46404/7 "2025-05-20T13:33:06Z")

</div>

Adding a Pane to the root StackPane will allow setting of static control position with setLayoutX()/setLayoutY(). Therefore, it will not be necessary to change the root pane in the runtime as proposed above. Presumably any of the other layout panes could be added to the pre-existing root pane, although this has yet to be tested.

```auto
// Adding a Pane to root StackPane will allow user to
// set control position with setLayoutX()/setLayoutY()

import javafx.scene.canvas.Canvas;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.Pane;

Canvas canvas;
StackPane root;
Pane pane;

void setup(){
  size(350,200,FX2D);
  surface.setTitle("JavaFX control in Default Wnd");
  canvas = (Canvas)surface.getNative();
  println("canvas =",canvas);
  root = (StackPane)canvas.getParent();
  println("root =",root);
  pane = new Pane();
  root.getChildren().add(pane);
  Button btn = new Button("Push Me");
  btn.setLayoutX(60);
  btn.setLayoutY(30);
  pane.getChildren().add(btn);
  println("pane =",pane);
}

```

**Output:**

 ![pane](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/8/9/89735ea41c5bb408b75bcbe50333dabd62c4cbbb.png)
