# JavaFX Controls in py5

**URL:** https://discourse.processing.org/t/javafx-controls-in-py5/45800
**Category:** py5
**Created:** [February 19, 2025, 8:17pm UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800 "2025-02-19T20:17:06Z")
**Posts on this page:** 18
**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: [February 19, 2025, 8:17pm UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/1 "2025-02-19T20:17:06Z")

</div>

The following source code demonstrates using javafx controls in py5. This demo may be run in the Thonny editor using ‘Imported mode for py5’. In addition, copies of the _seven javafx.xxxx.jar_ files and a copy of _javafx.jar_ must be in a folder entitled ‘jars’ in the py5 sketch folder. These may be copy/pasted from your Processing libraries folder; on MacOS the jar files are located at the following path: _Documents/Processing/libraries/javafx/library/yourOSFolder/modules/seven javafx.xxxxx.jar_ files. The javafx.jar is found in the ‘library’ folder (making eight jar files copy/pasted to the ‘jars’ folder). Disclaimer: May not work in Windows.

```python
# Uses Imported mode for py5
import javafx.stage.Stage

global pane

def toggleBtnAction(event):
  global toggleBtn
  if(toggleBtn.getText() == "Off"):
    toggleBtn.setText("On")
  else:
    toggleBtn.setText("Off")

def dialogBtnAction(self):
  global dialog
  dialog.showAndWait()
  
def sliderBtnAction(self):
  global myCircle
  global slider
  myCircle.setRadius(slider.getValue())
  
def colorPickerAction(self):
  global colorPicker
  global label
  global myCircle
  label.setTextFill(colorPicker.getValue())
  myCircle.setFill(colorPicker.getValue())

def datePickerAction(self):
  global datePicker
  value = datePicker.getValue()
  
def listViewListener(self):
  global listView
  label.setText(str(listView.getSelectionModel().getSelectedItem()))
  
def addControls():
  global toggleBtn
  global dialog
  global myCircle
  global slider
  global colorPicker
  global label
  global datePicker
  global listView
  
# Pane
  pane = javafx.scene.layout.Pane()

# Label
  label = javafx.scene.control.Label("Label")
  font = javafx.scene.text.Font.font("Menlo", javafx.scene.text.FontWeight.BOLD, javafx.scene.text.FontPosture.REGULAR, 15)
  label.setFont(font)
  label.setTextFill(javafx.scene.paint.Color.RED)
  label.setTranslateX(60)
  label.setTranslateY(65)
  pane.getChildren().add(label)

# Toggle Button
  toggleBtn = javafx.scene.control.ToggleButton("Off")
  toggleBtn.setLayoutX(390)
  toggleBtn.setLayoutY(140)
  toggleBtn.isSelected() == False
  toggleBtn.setOnAction(toggleBtnAction)
  pane.getChildren().add(toggleBtn)

# Button with Dialog
  dialog = javafx.scene.control.Dialog()
  dialog.setTitle("Error Dialog")
  btnType = javafx.scene.control.ButtonType("Ok")
  dialog.setContentText("Message goes here.")
  dialog.getDialogPane().getButtonTypes().add(btnType)
  btn = javafx.scene.control.Button("Push Me")
  btn.setLayoutX(80)
  btn.setLayoutY(20)
  btn.setOnAction(dialogBtnAction)
  pane.getChildren().add(btn)

# Circle
  myCircle = javafx.scene.shape.Circle(400, 60, 20)
  myCircle.setFill(javafx.scene.paint.Color.GREEN)
  pane.getChildren().add(myCircle)

# Slider
  slider = javafx.scene.control.Slider(1, 50, 10)
  slider.setLayoutX(190)
  slider.setLayoutY(20)
  tooltip1 = javafx.scene.control.Tooltip("Sets radius")
  slider.setTooltip(tooltip1)
  slider.setOnMouseDragged(sliderBtnAction)
  pane.getChildren().add(slider)

# Spinner
  spinner = javafx.scene.control.Spinner(0, 255, 0)
  spinner.setPrefSize(70, 25)
  spinner.setLayoutX(480)
  spinner.setLayoutY(60)
  pane.getChildren().add(spinner)

# ComboBox
  combo = javafx.scene.control.ComboBox()
  combo.setPromptText("Select One")
  myList = combo.getItems()
  myList.add("Java")
  myList.add("C++")
  myList.add("Python")
  myList.add("Processing")
  combo.setLayoutX(560)
  combo.setLayoutY(70)
  pane.getChildren().add(combo)

# ListView
  items = javafx.collections.FXCollections.observableArrayList("Item 1", "Item 2", "Item 3")
  listView = javafx.scene.control.ListView(items)
  listView.setMaxSize(120, 80)
  listView.setLayoutX(60)
  listView.setLayoutY(90)
  listView.getSelectionModel().selectedItemProperty().addListener(listViewListener)
  pane.getChildren().add(listView)

# TabPane
  tabPane = javafx.scene.control.TabPane()
  tabPane.setLayoutX(30)
  tabPane.setLayoutY(190)
  tab1 = javafx.scene.control.Tab("Tab 1")
  tab2 = javafx.scene.control.Tab("Tab 2")
  tab3 = javafx.scene.control.Tab("Tab 3")
  tab1.setContent(javafx.scene.shape.Rectangle(200, 100, javafx.scene.paint.Color.BLUE))
  tab2.setContent(javafx.scene.shape.Rectangle(200, 100, javafx.scene.paint.Color.RED))
  tab3.setContent(javafx.scene.shape.Rectangle(200, 100, javafx.scene.paint.Color.GREEN))
  tabPane.getTabs().addAll(tab1, tab2, tab3)
  pane.getChildren().add(tabPane)
  
# TextArea
  txtArea = javafx.scene.control.TextArea()
  txtArea.setLayoutX(250)
  txtArea.setLayoutY(190)
  txtArea.setMaxSize(180, 130)
  pane.getChildren().add(txtArea)

# RadioButton Group
  radioPane = javafx.scene.layout.TilePane(15, 15)
  group = javafx.scene.control.ToggleGroup()
  radio1 = javafx.scene.control.RadioButton("A")
  radio1.setToggleGroup(group)
  radio1.setSelected(True)
  radio2 = javafx.scene.control.RadioButton("B")
  radio2.setToggleGroup(group)
  radio3 = javafx.scene.control.RadioButton("C")
  radio3.setToggleGroup(group)
  radioPane.getChildren().addAll(radio1, radio2, radio3)
  radioPane.setLayoutX(200)
  radioPane.setLayoutY(120)
  pane.getChildren().add(radioPane)

# CheckBox
  cBox = javafx.scene.control.CheckBox("Checkbox")
  cBox.setIndeterminate(False)
  cBox.setLayoutX(200)
  cBox.setLayoutY(90)
  pane.getChildren().add(cBox)

# TextField
  txtFld = javafx.scene.control.TextField()
  txtFld.setLayoutX(200)
  txtFld.setLayoutY(150)
  pane.getChildren().add(txtFld)

# MenuBar **** //
  menu = javafx.scene.control.Menu("File")
  menuItem1 = javafx.scene.control.MenuItem("Open")
  menuItem2 = javafx.scene.control.MenuItem("Save")
  menu.getItems().addAll(menuItem1, menuItem2)
  menuBar = javafx.scene.control.MenuBar()
  menuBar.getMenus().add(menu)
  pane.getChildren().add(menuBar)

# ToolBar **** //
  toolBar = javafx.scene.control.ToolBar()
  openBtn = javafx.scene.control.Button("Build")
  saveBtn = javafx.scene.control.Button("Run")
  toolBar.getItems().addAll(openBtn, saveBtn)
  toolBar.setLayoutX(450)
  tbarTip = javafx.scene.control.Tooltip("ToolBar")
  toolBar.setTooltip(tbarTip)
  pane.getChildren().add(toolBar)

# ProgressBar
  pBar = javafx.scene.control.ProgressBar()
  pBar.setLayoutX(560)
  pBar.setLayoutY(20)
  pane.getChildren().add(pBar)

# TreeView **** //
  rootItem = javafx.scene.control.TreeItem("Pets")
  dogItem = javafx.scene.control.TreeItem("Dogs")
  dogItem.getChildren().add(javafx.scene.control.TreeItem("Poodle"))
  dogItem.getChildren().add(javafx.scene.control.TreeItem("Collie"))
  dogItem.getChildren().add(javafx.scene.control.TreeItem("Bulldog"))
  rootItem.getChildren().add(dogItem)

  catItem = javafx.scene.control.TreeItem("Cats")
  catItem.getChildren().add(javafx.scene.control.TreeItem("Siamese"))
  catItem.getChildren().add(javafx.scene.control.TreeItem("Ragdoll"))
  catItem.getChildren().add(javafx.scene.control.TreeItem("Persian"))
  rootItem.getChildren().add(catItem)

  treeView = javafx.scene.control.TreeView()
  treeView.setRoot(rootItem)
  treeView.setLayoutX(460)
  treeView.setLayoutY(110)
  treeView.setMaxSize(140, 230)
  treeView.setShowRoot(True)
  pane.getChildren().add(treeView)

# ColorPicker
  colorPicker = javafx.scene.control.ColorPicker()
  colorPicker.setLayoutX(200)
  colorPicker.setLayoutY(50)
  colorPicker.setValue(javafx.scene.paint.Color.GREEN)
  colorPicker.setOnAction(colorPickerAction) 
  pane.getChildren().add(colorPicker)

# DatePicker
  datePicker = javafx.scene.control.DatePicker()
  datePicker.setLayoutX(30)
  datePicker.setLayoutY(350)
  datePicker.setOnAction(datePickerAction) 
  pane.getChildren().add(datePicker)

# Line Chart
  xAxis = javafx.scene.chart.NumberAxis()
  xAxis.setLabel("No. of months")
  yAxis = javafx.scene.chart.NumberAxis()
  yAxis.setLabel("Dollars Per Dozen")
  lineChart = javafx.scene.chart.LineChart(xAxis, yAxis)
  dataSeries1 = javafx.scene.chart.XYChart.Series()
  dataSeries1.setName("2024")
  dataSeries1.getData().add(javafx.scene.chart.XYChart.Data( 1, 2))
  dataSeries1.getData().add(javafx.scene.chart.XYChart.Data( 2, 3))
  dataSeries1.getData().add(javafx.scene.chart.XYChart.Data(3, 4))
  dataSeries1.getData().add(javafx.scene.chart.XYChart.Data(4, 5))
  dataSeries1.getData().add(javafx.scene.chart.XYChart.Data(5, 6))
  dataSeries1.getData().add(javafx.scene.chart.XYChart.Data(6, 6))
  lineChart.getData().add(dataSeries1)
  lineChart.setTitle("Price of Eggs")
  lineChart.setLayoutX(280)
  lineChart.setLayoutY(350)
  lineChart.setMaxSize(320, 240)
  pane.getChildren().add(lineChart)
  
  return pane

def settings():
  size(1, 1, FX2D)
  
def setup():  
  stage = javafx.stage.Stage()
  stage.setTitle("JavaFX Controls")
  pane = addControls()
  scene = javafx.scene.Scene(pane, 700, 600)
  stage.setScene(scene)
  stage.show()

```

**Output:**

 ![jfx_ctrls](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/3/2/32d4d6cca01596f3b3134669ce8dbe3bc2371ec7.jpeg)

---

<div class="post-metadata">

### Author: ![hx2A](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/hx2a/32/14322_2.png) [@hx2A](https://discourse.processing.org/u/hx2A)
#### Post date: [February 24, 2025, 6:49am UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/2 "2025-02-24T06:49:27Z")

</div>

I’d love to find a way to combine these controls with an FX2D sketch, with the controls in the same window as the drawing surface.

---

<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: [February 24, 2025, 8:06pm UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/3 "2025-02-24T20:06:13Z")

</div>

I presume that by ‘drawing surface’ you mean canvas. A canvas is a control just like a button; the programmer can control its size, location, and function. In the demo below the canvas occupies almost the entire window except for a strip at the top reserved for other controls.

```python
# Uses Imported mode for py5
import javafx.stage.Stage;

_wndW = 600
_wndH = 400
_topMargin = 60

def settings():
  size(1, 1, FX2D)
    
def setup():
  global gc
  global colorPicker
  
  stage = javafx.stage.Stage()
  stage.setTitle("JavaFX Drawing Demo")
  pane = javafx.scene.layout.Pane()
  
  # ****ColorPicker****
  colorPicker = javafx.scene.control.ColorPicker()
  colorPicker.setLayoutX(200)
  colorPicker.setLayoutY(10)
  colorPicker.setValue(javafx.scene.paint.Color.GREEN) 
  pane.getChildren().add(colorPicker)

# ****Canvas****
  canvas = javafx.scene.canvas.Canvas(_wndW, _wndH - _topMargin)
  gc = canvas.getGraphicsContext2D()
  gc.setLineWidth(2)
  gc.strokeRect(0, 0, _wndW, _wndH -_topMargin);
  canvas.setLayoutY(_topMargin)
  canvas.setOnMousePressed(MOUSE_PRESSED)
  canvas.setOnMouseDragged(MOUSE_DRAGGED)
  pane.getChildren().add(canvas)

  scene = javafx.scene.Scene(pane, _wndW, _wndH);
  stage.setScene(scene);
  stage.show();

def MOUSE_PRESSED(evnt):
  gc.moveTo(evnt.getX(), evnt.getY())

def MOUSE_DRAGGED(evnt):
  global colorPicker
  
  gc.lineTo( evnt.getX(), evnt.getY())
  gc.setStroke(colorPicker.getValue())
  gc.stroke()
  gc.setLineCap(javafx.scene.shape.StrokeLineCap.ROUND)
  gc.setLineJoin(javafx.scene.shape.StrokeLineJoin.ROUND)

  blur = javafx.scene.effect.BoxBlur()
  blur.setWidth(10)
  blur.setHeight(1)
  blur.setIterations(1)
  gc.setEffect(blur)

```

**Output:**

 ![jfx2](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/1/9/192457004ec0dad824fecdb453120e9e7e4078cb.png)

---

<div class="post-metadata">

### Author: ![hx2A](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/hx2a/32/14322_2.png) [@hx2A](https://discourse.processing.org/u/hx2A)
#### Post date: [February 24, 2025, 11:35pm UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/4 "2025-02-24T23:35:01Z")

</div>

My guess is that `py5.get_surface().get_native()` would return a JavaFX object of some kind that could somehow be embedded in a JavaFX window? It would be neat if you could use py5 drawing commands to draw something that is inside a JavaFX window that also has those controls on it.

---

<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: [February 25, 2025, 3:22am UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/5 "2025-02-25T03:22:04Z")

</div>

`It would be neat if you could use py5 drawing commands to draw something that is inside a JavaFX window that also has those controls on it.`

To the best of my knowledge it is not possible to have JavaFX controls in a window which supports standard py5 drawing commands. A py5 window with a FX2D renderer returns _PSurfaceFX$ResizableCanvas@703580bf_ for _‘get\_surface().get\_native()’_, not a JavaFX object. You can draw into the FX2D renderer window using standard Processing primitives (circle, rect, triangle, etc) in the draw() loop as we are accustomed to, but it will not accept JavaFX controls without using a stage, scene, and pane (which creates another window). If you used a P2D renderer you could mix cp5 controls with standard drawing but the graphics is not quite as sharp as those with a FX2D renderer. The only way to have higher resolution graphics with snazzier controls is to use FX2D with JavaFX all the way. JavaFX has its own set of graphic shapes, but of course it’s more code. Examples are shown below.

**Py5 window with FX2D renderer:**

```python
# Uses Imported mode for py5

_wndW = 450
_wndH = 350

def setup():
  size(_wndW, _wndH, FX2D)
  window_title("Sketch Drawing")
  print(get_surface().get_native())

def draw():
  fill(0)
  text_size(32)
  text("FX2D Renderer Text",80,60)
  fill(255,0,0)
  circle(100,150,100)
  fill(0,0,255)
  triangle(220,100,170,200,270,200)
  fill(0,255,0)
  rect(300,100,100,100)

```

**Output:**

 ![1](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/4/5/456d12a8d46019929f8d141a92f99cac97952934.png)

**Py5 window with P2D renderer and cp5 controls:**

```python
# Uses Imported mode for py5
from controlP5 import *

_wndW = 450
_wndH = 350

def setup():
  global btn1
  
  size(_wndW, _wndH, P2D)
  window_title("Sketch Drawing")
  print(get_surface().get_native())
  cp5 = ControlP5(get_current_sketch())
  btn1 = Button(cp5,"Hello") 

def draw():
  fill(0)
  text_size(32)
  text("P2D Renderer Text",80,60)
  fill(255,0,0)
  circle(100,150,100)
  fill(0,0,255)
  triangle(220,100,170,200,270,200)
  fill(0,255,0)
  rect(300,100,100,100)
  
def mouse_pressed(e):
  if(btn1.isPressed()):
    print("btn1 was pressed.")

```

**Output:**

 ![2](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/8/c/8ce9eb79e31990f21c097e2fc6652de9a71c8bd1.png)

**Py5 window with JavaFX and FX2D renderer:**

```python
# Uses Imported mode for py5
import javafx.stage.Stage;

_wndW = 600
_wndH = 300

def myBtnAction(event):
    print("btn hit.")
    
def settings():
  size(1,1,FX2D)
  print(get_surface())
  
def setup():
  stage = javafx.stage.Stage()
  print("stage =",stage)
  stage.setTitle("JavaFX Graphics Demo")
# stage.setResizable:true  
  pane = javafx.scene.layout.Pane()

# Button
  btn = javafx.scene.control.Button("Button")
  btn.setLayoutX(90)
  btn.setLayoutY(10)
  btn.setOnAction(myBtnAction)
  pane.getChildren().add(btn)
  
# Text
  txt = javafx.scene.text.Text(130, 80, "Welcome to JavaFX!")
  txt.setFont(javafx.scene.text.Font(35))
  pane.getChildren().add(txt)
  
# Rectangle
  r = javafx.scene.shape.Rectangle(50, 130, 100, 50)
  r.setStroke(javafx.scene.paint.Color.color(0.0, 1.0, 0.0, 0.95))
  r.setStrokeWidth(5)
  r.setArcWidth(15)
  r.setArcHeight(15)
  pane.getChildren().add(r);
  
# Circle
  myCircle = javafx.scene.shape.Circle(250, 160, 40)
  myCircle.setFill(javafx.scene.paint.Color.DARKRED)
  myCircle.setStrokeWidth(6)
  myCircle.setStroke(javafx.scene.paint.Color.DARKSLATEBLUE)
  pane.getChildren().add(myCircle)

# Triangle
  polygon = javafx.scene.shape.Polygon();
  polygon.getPoints().addAll([380.0, 100.0, 330.0, 200.0, 430.0, 200.0])
  polygon.setFill(javafx.scene.paint.Color.GREEN)
  pane.getChildren().add(polygon)
  
# Line
  ln = javafx.scene.shape.Line(450,150,550,150)
  ln.setStroke(javafx.scene.paint.Color.color(1.0, 0.0, 0.0, 1.0))
  ln.setStrokeWidth(10)
  pane.getChildren().add(ln)
  
  scene = javafx.scene.Scene(pane, _wndW, _wndH, javafx.scene.paint.Color.ALICEBLUE)
  stage.setScene(scene)
  stage.show()

```

**Output:**

 ![3](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/a/e/aee6bb4b6e3b3112502a5cffb4b3c666edcbad1a.png)

---

<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: [February 25, 2025, 10:31pm UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/6 "2025-02-25T22:31:46Z")

</div>

If we rummage around in PSurfaceFX there is a ‘stage’ so the runtime is already using JavaFX for the FX2D renderer. It is possible to get a javafx control added to a pane container and to make the pane part of a scene, but it chokes when it comes time to set the scene on the stage and show it.

```python
# https://github.com/processing/processing/blob/master/core/src/processing/javafx/PSurfaceFX.java
import javafx.stage.Stage

_wndW = 300
_wndH = 300

def setup():
    size(_wndW,_wndH,FX2D)
    frame = get_surface()
    print("frame =",frame)
    pane = javafx.scene.layout.Pane()
    btn = javafx.scene.control.Button("btn")
    btn.setLayoutX(100)
    btn.setLayoutY(30)
    pane.getChildren().add(btn)
    print("pane =",pane)
    print("btn =",pane.getChildren())
    canvas = get_surface().get_native()
    canvas.prefHeight(240)
    print("canvas =",canvas)
    pane.setVisible(True)
    scene = javafx.scene.Scene(pane)
    print("scene =",scene)
    stage = canvas.getStage()
    print("stage =",stage)
# stage.setScene(scene)
# stage.show()

def draw():
  circle(100,200,50) 

```

**Error message:**

 ![err](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/7/4/74ed796189c5e734cc55a8351f6c7da5b434f01a.png)

**Output:** (attempt to put a JavaFX button in the window failed)

 ![out](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/e/f/ef503744f607f6e808eb94bd46222039e391823e.png)

**Addendum:**  
If we pause the thread right before stage.setScene() the button is shown but the circle is lost.  
**New Output:**

 ![out2](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/0/d/0d34c99377f62f1eccbc6f25f535a1a2ecc0fc1c.png)

---

<div class="post-metadata">

### Author: ![hx2A](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/hx2a/32/14322_2.png) [@hx2A](https://discourse.processing.org/u/hx2A)
#### Post date: [February 26, 2025, 12:56am UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/7 "2025-02-26T00:56:12Z")

</div>

> [@svan](#):
>
> If we rummage around in PSurfaceFX there is a ‘stage’ so the runtime is already using JavaFX for the FX2D renderer.

A glimmer of hope! I bet it could be done by modifying the library’s `PGraphicsFX` class to use a replacement `PSurfaceFX` class that can better cooperate with these goals. That’s likely a hard thing to do though. But still possible.

---

<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: [February 26, 2025, 1:52am UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/8 "2025-02-26T01:52:34Z")

</div>

**Observation:** Notice the difference in the background colors. My interpretation of this is that there are two potential canvases: one for drawing and one for javafx controls. One or the other winds up being used but not both at the same time. With Swing controls I have slid the default canvas down to create a vacant strip at the top and then added Swing components to the strip. I would like to use a similar technique here, but I’m not sure javafx controls can be added to the bare frame using frame.add(control). It seems that they can only go in a stage and that creates a whole new window.

**Another Observation:** this is what shuts down drawing  
[processing/core/src/processing/javafx/PSurfaceFX.java at master · processing/processing · GitHub](https://github.com/processing/processing/blob/master/core/src/processing/javafx/PSurfaceFX.java) line 88

```auto
        try {
          sketch.handleDraw();
        } catch (Throwable e) {
          // Let exception handler thread crash with our exception
          drawExceptionQueue.offer(e);
          // Stop animating right now so nothing runs afterwards
          // and crash frame can be for example traced by println()
          animation.stop();
          return;
        }

```

Interestingly the draw loop keeps right on going; if you add _print(“x”)_ to draw() output shows up in the console.

---

<div class="post-metadata">

### Author: ![hx2A](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/hx2a/32/14322_2.png) [@hx2A](https://discourse.processing.org/u/hx2A)
#### Post date: [February 27, 2025, 4:43am UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/9 "2025-02-27T04:43:58Z")

</div>

I see. Processing’s JavaFX renderer has its own animation thread. Any attempt to commandeer the drawing surface and integrate it with controls would have to take over that also.

---

<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: [February 27, 2025, 6:52am UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/10 "2025-02-27T06:52:13Z")

</div>

I wonder what would happen if we forked the editor, remmed out that line and recompiled it. Would be interesting to see the effect; there likely was some good reason why the author thought it was necessary to stop animation in the first place. The FX2D window appears to be chimeric; on one hand it can take regular Processing drawing commands and on the other hand it can be turned into a JavaFX window (stage).

---

<div class="post-metadata">

### Author: ![hx2A](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/hx2a/32/14322_2.png) [@hx2A](https://discourse.processing.org/u/hx2A)
#### Post date: [February 27, 2025, 2:57pm UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/11 "2025-02-27T14:57:31Z")

</div>

Processing’s renderers are fascinating to dive into but this requires more time than I have right now. I did make a note to explore it further later, when I have more time.

---

<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: [February 27, 2025, 6:31pm UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/12 "2025-02-27T18:31:44Z")

</div>

I’m unable to find PSurfaceFX on current website: [https://github.com/processing/processing4](https://github.com/processing/processing4) ; I did several searches.

---

<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: [February 27, 2025, 6:35pm UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/13 "2025-02-27T18:35:13Z")

</div>

> **[processing/core/src/processing/javafx at master · processing/processing](https://github.com/processing/processing/tree/master/core/src/processing/javafx)**
>
> Source code for the Processing Core and Development Environment (PDE) - processing/processing

---

<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: [February 27, 2025, 6:56pm UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/14 "2025-02-27T18:56:49Z")

</div>

Thanks. I thought that the current editor was coming from the website that I listed, but I’ll give this one a try.

**Addendum:** I don’t see any way to fork this one.

---

<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: [February 27, 2025, 7:09pm UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/15 "2025-02-27T19:09:31Z")

</div>

Oh look, you can get two windows at one time:

```python
# Uses Imported mode for py5
import javafx.stage.Stage;

_wndW = 600
_wndH = 250

def myBtnAction(event):
    print("btn hit.")
    
def settings():
  size(_wndW, _wndH, FX2D)
    
def setup():
 
  window_title("Default window")
  
  stage = javafx.stage.Stage()
  stage.setTitle("JavaFX Drawing Demo")
  pane = javafx.scene.layout.Pane()
  
# Button
  btn = javafx.scene.control.Button("Button")
  btn.setLayoutX(90)
  btn.setLayoutY(10)
  btn.setOnAction(myBtnAction)
  pane.getChildren().add(btn)
  
# Text
  txt = javafx.scene.text.Text(130, 80, "Welcome to JavaFX!")
  txt.setFont(javafx.scene.text.Font(35))
  pane.getChildren().add(txt)
  
# Rectangle
  r = javafx.scene.shape.Rectangle(50, 130, 100, 50)
  r.setStroke(javafx.scene.paint.Color.color(0.0, 1.0, 0.0, 0.95))
  r.setStrokeWidth(5)
  r.setArcWidth(15)
  r.setArcHeight(15)
  pane.getChildren().add(r);
  
# Circle
  myCircle = javafx.scene.shape.Circle(250, 160, 40)
  myCircle.setFill(javafx.scene.paint.Color.DARKRED)
  myCircle.setStrokeWidth(6)
  myCircle.setStroke(javafx.scene.paint.Color.DARKSLATEBLUE)
  pane.getChildren().add(myCircle)

# Triangle
  polygon = javafx.scene.shape.Polygon();
  polygon.getPoints().addAll([380.0, 100.0, 330.0, 200.0, 430.0, 200.0])
  polygon.setFill(javafx.scene.paint.Color.GREEN)
  pane.getChildren().add(polygon)
  
# Line
  ln = javafx.scene.shape.Line(450,150,550,150)
  ln.setStroke(javafx.scene.paint.Color.color(1.0, 0.0, 0.0, 1.0))
  ln.setStrokeWidth(10)
  pane.getChildren().add(ln)
  
  scene = javafx.scene.Scene(pane, _wndW, _wndH, javafx.scene.paint.Color.ALICEBLUE)
  stage.setScene(scene)
  stage.show()

def draw():
  fill(0)
  text_size(32)
  text("FX2D Renderer Text",80,60)
  fill(255,0,0)
  circle(100,150,100)
  fill(0,0,255)
  triangle(220,100,170,200,270,200)
  fill(0,255,0)
  rect(300,100,100,100)

```

**Output:**

 ![duo](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/d/2/d26f990c54a4e1dadf3c68739f8d8212f7b45d65.png)

---

<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: [March 1, 2025, 6:23am UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/16 "2025-03-01T06:23:17Z")

</div>

It’s possible to have controls in the JavaFX window control drawing in the Default FX2D window using standard Processing drawing calls. Note that size() parameters control the size of the default window and scene() parameters control the size of the JavaFX window.

```python
# Uses Imported mode for py5
import javafx.stage.Stage

_wndW = 700
_wndH = 600

global pane

def settings():
  size(_wndW, _wndH, FX2D)
  
def setup():
  global slider
  global colorPicker
  
  window_title("Processing Drawing")
  stage = javafx.stage.Stage()
  stage.setTitle("JavaFX Controls")
  pane = javafx.scene.layout.Pane()
  
  # Slider
  slider = javafx.scene.control.Slider(1, 500, 75)
  slider.setLayoutX(60)
  slider.setLayoutY(20)
  pane.getChildren().add(slider)
  
  # ColorPicker
  colorPicker = javafx.scene.control.ColorPicker()
  colorPicker.setLayoutX(70)
  colorPicker.setLayoutY(80)
  colorPicker.setValue(javafx.scene.paint.Color.GREEN)
  pane.getChildren().add(colorPicker)
  
  scene = javafx.scene.Scene(pane, 300, 200)
  stage.setScene(scene)
  stage.show()

def draw():
  global slider
  global colorPicker
  
  background(209)
  Color = colorPicker.getValue()
  fill(int(Color.getRed()*255),int(Color.getGreen()*255),int(Color.getBlue()*255))
  circle(_wndW/2,_wndH/2, float(slider.getValue()))

```

**Output:**

 ![2Wnd](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/1/3/13e28477648825ce31274146ddb72fbaabd81cd3.jpeg)

---

<div class="post-metadata">

### Author: ![hx2A](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/hx2a/32/14322_2.png) [@hx2A](https://discourse.processing.org/u/hx2A)
#### Post date: [March 3, 2025, 12:18am UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/17 "2025-03-03T00:18:46Z")

</div>

> [@svan](#):
>
> It’s possible to have controls in the JavaFX window control drawing in the Default FX2D window using standard Processing drawing calls.

Right, this is a straightforward approach that is easy to understand.

---

<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: [June 18, 2025, 4:11am UTC](https://discourse.processing.org/t/javafx-controls-in-py5/45800/18 "2025-06-18T04:11:47Z")

</div>

> [@hx2A](#):
>
> It would be neat if you could use py5 drawing commands to draw something that is inside a JavaFX window that also has those controls on it.

The FX2D window already has a StackPane (root) which is by default CENTER aligned. By adding a ‘regular’ Pane to the root we can then add JavaFX controls to it using setLayoutX/Y for control placement. _draw()_ is functional in this window and therefore allows us to use familiar Processing drawing code.

```python
import javafx

_wndW = 600
_wndH = 600
    
def setup():
  global slider,colorPicker
  
  size(_wndW, _wndH, FX2D)
  window_title("JavaFX DotView Default Window")  
  canvas = get_surface().get_native()
  root = canvas.getParent()
  pane = javafx.scene.layout.Pane()
  slider = javafx.scene.control.Slider(20, 500, 10)
  slider.setLayoutX(190)
  slider.setLayoutY(20)
  colorPicker = javafx.scene.control.ColorPicker(javafx.scene.paint.Color.GREEN)
  colorPicker.setLayoutX(400)
  colorPicker.setLayoutY(15)
  pane.getChildren().addAll(slider,colorPicker)
  root.getChildren().add(pane)
  
def draw():
  global slider, colorPicker
  
  background(209)
  Color = colorPicker.getValue()
  fill(int(Color.getRed()*255),int(Color.getGreen()*255),int(Color.getBlue()*255))
  circle(_wndW/2,_wndH/2, float(slider.getValue()))

```

**Output:**

 ![dvdw](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/a/f/af085864884a7db800f4bbc3e4d435205f2689d3.jpeg)
