# Swing Components in Default Processing Window\_py5

**URL:** https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482
**Category:** py5
**Created:** [May 24, 2024, 11:20am UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482 "2024-05-24T11:20:30Z")
**Posts on this page:** 20
**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 24, 2024, 11:20am UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/1 "2024-05-24T11:20:30Z")

</div>

To use Swing components in a default Processing window in py5 it is necessary to remove part or all of the canvas. By dropping the canvas down a little bit it is possible to use the top portion for Swing components and the bottom portion for conventional drawing using draw(). Please note that this demo was created in a _Thonny editor_ with a py5 plugin. The venerable DotView is shown below using the _imported mode of py5_:

```auto
# Use Imported mode for py5

from javax.swing import *
from java.awt import *

_wndW = 600
_wndH = 660

myColor = Color.GREEN

def myBtnAction(event):
    global myColor
    panel = JPanel()
    myColor = JColorChooser.showDialog(panel,"Choose color",Color.GREEN)
  
def setup():
    global frame
    global slider
    
    size(_wndW, _wndH)
    wnd = get_surface()    
    canvas = wnd.get_native()
    frame = canvas.getFrame()
    wnd.set_title('Default Processing Window')
    canvas.setBounds(0,60,_wndW,_wndH - 60)
          
    slider = JSlider(JSlider.HORIZONTAL, 0, 500, 100)
    slider.setBounds(180, 20, 200, 24)
    slider.setToolTipText("size");
    frame.add(slider)
    slider.repaint()
    
    btn = JButton("Color")
    btn.setBounds(400,20,80,24)
    frame.add(btn)
    btn.repaint()
    btn.addActionListener(myBtnAction)

def draw():
    background(209)
    fill(myColor.getRed(), myColor.getGreen(), myColor.getBlue())
    circle(300,300,slider.getValue())

```

**Output:**

 ![DotView_py5](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/8/6/86a14f054f811ebe9b631cb452d96f115bc6a5e4.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 25, 2024, 6:40am UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/2 "2024-05-25T06:40:20Z")

</div>

> [@svan](#):
>
> The venerable DotView is shown below using the _imported mode of py5_:

Converted your py5 Swing demo to “imported mode”, which can now be run outside Thonny:

```auto
import py5

from java.awt import Color
from javax.swing import JSlider, JButton, JColorChooser

fill = Color.GREEN

def setup():
    py5.size(600, 660)
    py5.fill(fill.getRGB())

    global cx, cy, slider
    cx, cy = py5.width >> 1, py5.height >> 1

    slider = JSlider(JSlider.HORIZONTAL, 0, 500, 100)
    slider.setBounds(180, 20, 200, 24)
    slider.setToolTipText('circle diameter')

    btn = JButton('Color')
    btn.setBounds(400, 20, 80, 24)
    btn.addActionListener(button_action)

    window = py5.get_surface()
    window.set_title('py5 Swing Demo')

    canvas = window.get_native()
    canvas.setBounds(0, 60, py5.width, py5.height - 60)

    frame = canvas.getFrame()
    frame.add(slider)
    frame.add(btn)

    slider.repaint()
    btn.repaint()

def draw():
    py5.background(0o320)
    py5.circle(cx, cy, slider.getValue())

def button_action(_, TITLE = 'Choose color:'):
    global fill
    fill = JColorChooser.showDialog(None, TITLE, fill) or fill
    py5.fill(fill.getRGB())

__name__ == ' __main__' and py5.run_sketch()

```

---

<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 25, 2024, 8:07am UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/3 "2024-05-25T08:07:49Z")

</div>

A more Java-ish version using `this = py5._instance`, so it’ more in line w/ both Java & Processing’s API _lowerCamelCase_ naming convention: ☕

```auto
"""
 * py5 Swing Demo (v1.0.0)
 * GoToLoop & Svan (2024/May/25)
 *
 * https://Discourse.Processing.org/t/
 * swing-components-in-default-processing-window-py5/3
"""

import py5

from java.awt.Color import GREEN
from javax.swing import JSlider, JLabel, JButton, JColorChooser

DIAM = 'Diameter: %d'

this = py5._instance
fill = GREEN

def settings(): this.size(600, 660)

def setup():
    this.noLoop()
    this.fill(fill.getRGB())

    global cx, cy, slider, label

    w, h = this.width, this.height
    cx, cy = w >> 1, h >> 1

    slider = JSlider(0, w - 60, cx)
    slider.setBounds(180, 20, 200, 24)
    slider.addChangeListener(slideChange)
    slider.setToolTipText('circle diameter')

    (label := JLabel(DIAM % cx)).setBounds(75, 20, 80, 24)

    btn = JButton('Color')
    btn.setBounds(400, 20, 80, 24)
    btn.addActionListener(btnAction)

    (window := this.getSurface()).setTitle('py5 Swing Demo')
    (canvas := window.getNative()).setBounds(0, 60, w, h - 60)

    frame = canvas.getFrame()
    frame.add(slider); frame.add(label); frame.add(btn)
    slider.repaint(); label.repaint(); btn.repaint()

def draw():
    this.background(0o320)
    this.circle(cx, cy, slider.getValue())

def mouse_wheel(e): slider.setValue(slider.getValue() - e.get_count() * 10)

def slideChange(_):
    label.setText(DIAM % slider.getValue())
    this.redraw()

def btnAction(_, TITLE = 'Choose color:'):
    global fill
    fill = JColorChooser.showDialog(None, TITLE, fill) or fill

    this.fill(fill.getRGB())
    this.redraw()

__name__ == ' __main__' and py5.run_sketch()

```

---

<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 25, 2024, 1:35pm UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/4 "2024-05-25T13:35:11Z")

</div>

It was already written using “Imported mode for py5” using the Thonny editor with plugin. By adding “import py5” at the top you converted it to “Module Mode” if I understand correctly. Reference is here: [https://py5coding.org/content/py5\_modes.html](https://py5coding.org/content/py5_modes.html) for the sake of others viewing this thread. All those ‘modes’ are confusing to me, but it appears that by using the plugin and imported mode the authors were trying to make it easier for rookies like me. Personally I don’t like having to add the _py5._ prefix to everything and your adaptation using _this._ is more like what I am accustomed to using. With the addition of JavaFX there should now be controls for py5 users to take advantage of. I’m assuming that you ran this code in the Windows environment, which is good if you did because it demonstrates that it will run across platforms. Should run in Linux too (confirmed by another user). Thanks for taking the time to look at it.

---

<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 25, 2024, 8:09pm UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/5 "2024-05-25T20:09:14Z")

</div>

> [@svan](#):
>
> I’m assuming that you ran this code in the Windows environment,

Yup, inside “cmd.exe” command prompt. But it should work on any terminal from any OS where both Java & Python are installed.

BtW, we can have multiple instances of the same Python file running at the same time.

Tip: Use pythonw sketch\_name.py or pyw sketch\_name.py to run a Python file w/o blocking the terminal’s command prompt.

> [@svan](#):
>
> With the addition of JavaFX there should now be controls for py5 users to take advantage of.

Unfortunately I couldn’t make py5 run your other [JavaFX demo](https://discourse.processing.org/t/javafx-in-py5-demo/44480). It throws:

> java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found  
> at com.sun.javafx.tk.quantum.QuantumRenderer.getInstance(QuantumRenderer.java:283)  
> at javafx.scene.Node.(Node.java:417)

I’ve copied all the “.jar” files into subfolder “jars/” btW.

---

<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 25, 2024, 9:16pm UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/6 "2024-05-25T21:16:38Z")

</div>

Is _javafx.jar_ in there with all the other javafx.xxxxx.jar files as shown below. I’m still trying to figure out the importance of those lib files.

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

I really would like to have that run on a Windows box. I have confirmation that it runs on Linux.

---

<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 25, 2024, 9:21pm UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/7 "2024-05-25T21:21:51Z")

</div>

I ran that demo in the Thonny editor with py5 plugin added and _‘Import mode for py5’_ on the menubar checked. We have not been able to run it from the cmd-line yet. I don’t know how to include the javafx jar files with _python3 … filename.py_

---

<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 25, 2024, 9:29pm UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/8 "2024-05-25T21:29:02Z")

</div>

./jars  
├── javafx.base.jar  
├── javafx.controls.jar  
├── javafx.fxml.jar  
├── javafx.graphics.jar  
├── javafx.jar  
├── javafx.media.jar  
├── javafx.swing.jar  
├── javafx.web.jar

---

<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: [June 3, 2024, 12:21pm UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/9 "2024-06-03T12:21:07Z")

</div>

Java Mode version sketch for Processing 3 & 4: ☕

```auto
/**
 * Processing Java Mode Swing Demo (v1.0.2)
 * GoToLoop (2024/Jun/03)
 *
 * https://Discourse.Processing.org/t/
 * swing-components-in-default-processing-window-py5/9
 */

import java.awt.Color;
import java.awt.Frame;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;

import javax.swing.JSlider;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JColorChooser;

import processing.awt.PSurfaceAWT.SmoothCanvas;

static final String TITLE = "Choose color:", DIAM = "Diameter: ";

Color fill = Color.GREEN;

JSlider slider;
JLabel label;

int cx, cy;

void settings() {
  size(600, 660);
  noLoop();
}

void setup() {
  fill(fill.getRGB());

  cx = width >> 1;
  cy = height >> 1;

  slider = new JSlider(0, width - 60, cx);
  slider.setBounds(180, 20, 200, 24);
  slider.addChangeListener(slideChange);
  slider.setToolTipText("circle diameter");

  (label = new JLabel(DIAM + cx)).setBounds(75, 20, 80, 24);

  final JButton btn = new JButton("Color");
  btn.setBounds(400, 20, 80, 24);
  btn.addActionListener(btnAction);

  final PSurface window = getSurface();
  window.setTitle("Processing Java Mode Swing Demo");

  final SmoothCanvas canvas = (SmoothCanvas)window.getNative();
  canvas.setBounds(0, 60, width, height - 60);

  final Frame frame = canvas.getFrame();
  frame.add(slider);
  frame.add(label);
  frame.add(btn);

  slider.repaint();
  label.repaint();
  btn.repaint();
}

void draw() {
  background(0320);
  circle(cx, cy, slider.getValue());
}

void mouseWheel(final MouseEvent e) {
  slider.setValue(slider.getValue() - e.getCount() * 10);
}

final ChangeListener slideChange = new ChangeListener() {
  final void stateChanged(final ChangeEvent __) {
    label.setText(DIAM + slider.getValue());
    redraw();
  }
};

final ActionListener btnAction = new ActionListener() {
  final void actionPerformed(final ActionEvent __) {
    final Color chosenColor = JColorChooser.showDialog(null, TITLE, fill);
    if (chosenColor == null) return;

    fill((fill = chosenColor).getRGB());
    redraw();
  }
};

```

P.S.: The sketch can be refactored to be less verbose for Processing 4.

---

<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: [June 3, 2024, 1:05pm UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/10 "2024-06-03T13:05:30Z")

</div>

And for completeness’ sake, also a Python Mode (Jython) for Processing 3: 🐍

```py
"""
 * Processing Python Mode Swing Demo (v1.0.2)
 * GoToLoop (2024/Jun/03)
 *
 * https://Discourse.Processing.org/t/
 * swing-components-in-default-processing-window-py5/10
"""

from java.awt.Color import GREEN
from javax.swing import JSlider, JLabel, JButton, JColorChooser

DIAM = 'Diameter: %d'
c = GREEN

def setup():
    size(600, 660)
    noLoop()
    fill(c.RGB)

    global cx, cy, slider, label

    w, h = width, height
    cx, cy = w >> 1, h >> 1

    slider = JSlider(0, w - 60, cx, bounds = (180, 20, 200, 24))
    slider.addChangeListener(slideChange)
    slider.toolTipText = 'circle diameter'

    label = JLabel(DIAM % cx, bounds = (75, 20, 80, 24))

    btn = JButton('Color', bounds = (400, 20, 80, 24))
    btn.addActionListener(btnAction)

    window = this.surface
    window.title = 'Processing Python Mode Swing Demo'

    canvas = window.native
    canvas.bounds = 0, 60, w, h - 60

    frame = canvas.frame
    frame.add(slider); frame.add(label); frame.add(btn)
    slider.repaint(); label.repaint(); btn.repaint()

def draw(): background(0320); circle(cx, cy, slider.value)

def mouseWheel(e): slider.value -= e.count * 10

def slideChange(_): label.text = DIAM % slider.value; redraw()

def btnAction(_, TITLE = 'Choose color:'):
    global c
    c = JColorChooser.showDialog(None, TITLE, c) or c
    fill(c.RGB); redraw()

```

---

<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 3, 2024, 5:09pm UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/11 "2024-06-03T17:09:29Z")

</div>

For those not interested in the py5 Python version and no regard for backward compatibility, the following is my Processing 4 version of DotView:

```auto
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

javax.swing.JFrame frame;
java.awt.Canvas canvas;

int diameter = 150;
Color dotColor = Color.GREEN;

int _wndW = 700;
int _wndH = 600;

void colorBtn(int x, int y, int w, int h) {
  JButton btn = new JButton("Color");
  btn.setBounds(x, y, w, h);
  frame.add(btn);
  btn.addActionListener( new ActionListener() {
    void actionPerformed(ActionEvent actionEvent) {
      dotColor = JColorChooser.showDialog(null, "Choose color", Color.GREEN);
    }
  }
  );
}

void sizeSlider(int x, int y, int w, int h) {
  // orientation, min, max, value
  JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 450, 150);
  slider.setBounds(x, y, w, h);
  frame.add(slider);
  slider.addChangeListener(new ChangeListener() {
    void stateChanged(ChangeEvent changeEvent) {
      diameter = slider.getValue();
    }
  }
  );
}

void buildWnd() {
  sizeSlider(180, 20, 200, 24);
  colorBtn(390, 20, 80, 24);
  frame.setVisible(true);
}

void setup() {
  size(_wndW, _wndH); // Makes it possible to use draw();
  frame = (javax.swing.JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas) surface.getNative()).getFrame();
  canvas = (processing.awt.PSurfaceAWT.SmoothCanvas) ((processing.awt.PSurfaceAWT)surface).getNative();
  frame.setBounds(900, 300, _wndW, _wndH); // Makes it possible to add swing components
  frame.setLayout(null);
  canvas.setBounds(0, 60, _wndW, _wndH-60); // For use with draw()
  javax.swing.SwingUtilities.invokeLater(()-> {
      buildWnd(); // Builds components on EventDispatchThread
  }
  );
}

void draw() {
  background(209);
  fill(dotColor.getRed(),dotColor.getGreen(),dotColor.getBlue());
  stroke(0);
  strokeWeight(2.0);
  circle(_wndW/2, _wndH/2 - 50, diameter);
}

```

**Addendum:**  
I note that you did not use a separate EventDispatchThread in your demo. There’s only two components so it might not be an issue. I have no idea what behaviour is seen if it is an issue.

---

<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: [June 3, 2024, 10:44pm UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/12 "2024-06-03T22:44:44Z")

</div>

> [@svan](#):
>
> … and no regard for backward compatibility, the following is my Processing 4 version…:

Made the minimum required changes to your latest code so it runs on Processing 3 as well: 😉

```auto
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

javax.swing.JFrame frame;
java.awt.Canvas canvas;

int diameter = 150;
Color dotColor = Color.GREEN;

void colorBtn(int x, int y, int w, int h) {
  JButton btn = new JButton("Color");
  btn.setBounds(x, y, w, h);
  frame.add(btn);
  btn.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent actionEvent) {
      dotColor = JColorChooser.showDialog(null, "Choose color", Color.GREEN);
    }
  }
  );
}

void sizeSlider(int x, int y, int w, int h) {
  // orientation, min, max, value
  final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 450, 150);
  slider.setBounds(x, y, w, h);
  frame.add(slider);
  println(frameCount);
  slider.addChangeListener(new ChangeListener() {
    public void stateChanged(ChangeEvent changeEvent) {
      diameter = slider.getValue();
    }
  }
  );
}

void buildWnd() {
  sizeSlider(180, 20, 200, 24);
  colorBtn(390, 20, 80, 24);
  frame.setVisible(true);
}

void setup() {
  size(700, 600); // Makes it possible to use draw();
  frame = (javax.swing.JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas) surface.getNative()).getFrame();
  canvas = (processing.awt.PSurfaceAWT.SmoothCanvas) ((processing.awt.PSurfaceAWT)surface).getNative();
  frame.setBounds(900, 300, width, height); // Makes it possible to add swing components
  frame.setLayout(null);
  canvas.setBounds(0, 60, width, height-60); // For use with draw()
  javax.swing.SwingUtilities.invokeLater(new Runnable() {
    public void run() {
      buildWnd(); // Builds components on EventDispatchThread
    }
  }
  );
}

void draw() {
  background(209);
  fill(dotColor.getRed(), dotColor.getGreen(), dotColor.getBlue());
  stroke(0);
  strokeWeight(2.0);
  circle(width/2, height/2 - 50, diameter);
}

```

Basically replaced the lambda `->` thin arrow syntax w/ a `new` Runnable callback.

Also replaced _\_wndW_ & _\_wndH_ w/ _width_ & _height_ respectively, so no **settings()** callback is required for **size()**.

And lastly, added keywords `public` & `final` where they were required for the listeners’ callbacks.

---

<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: [June 4, 2024, 12:55am UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/13 "2024-06-04T00:55:02Z")

</div>

> [@svan](#):
>
> I note that you did not use a separate EventDispatchThread in your demo.

Do you mean no callback for SwingUtilities.[**invokeLater()**](https://docs.oracle.com/en/java/javase/17/docs/api/java.desktop/javax/swing/SwingUtilities.html#invokeLater(java.lang.Runnable))?  
Well, you haven’t added 1 for your original py5 sketch either!  
And all of my sketches here are based on your 1st py5 sketch!

Although it’s indeed highly recommended to use **invokeLater()** to do anything related to Swing components, sketches that directly create and add simple components within **setup()** had no issues since Processing 1!

A Processing sketch by default has only 2 active threads:  
The “Animation Thread” & the “AWT-EventQueue-0” (EDT) for the JAVA2D renderer.

Code running within **setup()** and on is already under the “Animation Thread” btW.

The reason why code running under the “Animation Thread” can manipulate AWT/Swing GUI w/o any repercussions is b/c there’s no other thread doing the same at the same time.

The “Animation Thread” only deals w/ the Swing JFrame when it updates its canvas after **draw()** is done.

So any code running under the “Animation Thread” is guaranteed not to mutate the GUI while Processing is busy repainting/updating its canvas.

---

<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 4, 2024, 2:01am UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/14 "2024-06-04T02:01:26Z")

</div>

Your second demo was a conversion of a py5 demo to a Processing app, and I use a separate EventDispatchThread in Processing apps at the recommendation of others in this forum:  
[https://discourse.processing.org/t/swing-components-in-default-processingwindow/35483](https://discourse.processing.org/t/swing-components-in-default-processingwindow/35483)  
However, I have not been using a separate thread for Swing components in py5 simply because it has never caused any problems as far as I’m aware and I am unable to find any good references on how to add it in Python. Py5 appears to have insulated us from this problem, but I am not aware of how this has been accomplished under the hood; I have not dissected the source code. The issue has recently come up in their forum with regard to using Swing components _without_ using py5 and here a separate thread seems to be necessary also. Furthermore, source code posted in JPype documentation which deals with Swing components and a separate EventDispatchThread won’t run on a Mac for some reason and as far I know there is no published fix for Macs: [https://jpype.readthedocs.io/en/latest/userguide.html#awt-swing](https://jpype.readthedocs.io/en/latest/userguide.html#awt-swing). It’s in the AWT/Swing section. I would love for somebody to show me how it’s done or find it published somewhere, but I can’t find it. The only reason I use it in Processing is because I was cautioned when I posted the first demo here some time back (referenced above), and it seems pretty well accepted that Swing is not ‘thread safe’, whatever that entails. I respect the experiences of others. When I use Swing components in Processing I frequently remove the canvas, so there is no draw() available to use. Perhaps it’s still being used by the runtime, I don’t know about that. DotView, recently published, preserves part of the canvas so draw() is functional in this instance.

---

<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: [June 4, 2024, 1:31pm UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/15 "2024-06-04T13:31:53Z")

</div>

> [@svan](#):
>
> However, I have not been using a separate thread for Swing components in py5 simply because it has never caused any problems as far as I’m aware…

> [@svan](#):
>
> Py5 appears to have insulated us from this problem,

AFAIK, there’s nothing in py5 or JPype that would make Java threads any safer!

If you feel the need to use SwingUtilities.**invokeLater()** in Processing’s Java Mode, you should also take the same precautions on py5 too!

> [@svan](#):
>
> … and I am unable to find any good references on how to add it in Python.

“py5 Swing Demo II” is using SwingUtilities.**invokeLater()** now:

```py
"""
 * py5 Swing Demo II (v1.0.0)
 * GoToLoop & Svan (2024/Jun/04)
 *
 * https://Discourse.Processing.org/t/
 * swing-components-in-default-processing-window-py5/15
"""

import py5

from java.awt.Color import GREEN
from javax.swing import JSlider, JLabel, JButton, JColorChooser, SwingUtilities

DIAM = 'Diameter: %d'
USE_INVOKE_LATER = True

this = py5._instance
fill = GREEN

def settings(): this.size(600, 660)

def setup():
    this.noLoop()
    this.fill(fill.getRGB())

    global w, h, cx, cy
    w, h = this.width, this.height
    cx, cy = w >> 1, h >> 1

    if USE_INVOKE_LATER: # delegate GUI creation to run on the EDT thread
        SwingUtilities.invokeLater(createGUI)
        while 'slider' not in globals(): this.delay(100)

    else: createGUI() # keep Swing GUI creation on the Animation thread

def draw():
    this.background(0o320)
    this.circle(cx, cy, slider.getValue())

def mouse_wheel(e): slider.setValue(slider.getValue() - e.get_count() * 10)

def createGUI():
    global slider, label

    slider = JSlider(0, w - 60, cx)
    slider.setBounds(180, 20, 200, 24)
    slider.addChangeListener(slideChange)
    slider.setToolTipText('circle diameter')

    (label := JLabel(DIAM % cx)).setBounds(75, 20, 80, 24)

    btn = JButton('Color')
    btn.setBounds(400, 20, 80, 24)
    btn.addActionListener(btnAction)

    (window := this.getSurface()).setTitle('py5 Swing Demo')
    (canvas := window.getNative()).setBounds(0, 60, w, h - 60)

    frame = canvas.getFrame()
    frame.add(slider); frame.add(label); frame.add(btn)
    slider.repaint(); label.repaint(); btn.repaint()

def slideChange(_):
    label.setText(DIAM % slider.getValue())
    this.redraw()

def btnAction(_, TITLE = 'Choose color:'):
    global fill
    fill = JColorChooser.showDialog(None, TITLE, fill) or fill

    this.fill(fill.getRGB())
    this.redraw()

__name__ == ' __main__' and py5.run_sketch()

```

This new version is exactly the same as previous “py5 Swing Demo”, but w/ a constant USE\_INVOKE\_LATER, which we can toggle `True` or `False` before running the code.

When USE\_INVOKE\_LATER is `False`, it behaves exactly like its previous original version btW; using Processing’s Animation thread to build its Swing GUI components.

Also notice I had to pause the sketch execution inside **setup()** by invoking **delay()** inside a `while` loop, awaiting for **createGUI()** under EDT thread, so **draw()** doesn’t start running until global variable _slider_ exists:

```py
    if USE_INVOKE_LATER: # delegate GUI creation to run on the EDT thread
        SwingUtilities.invokeLater(createGUI)
        while 'slider' not in globals(): this.delay(100)

```

As you can notice, we can pass any Python function as an argument for SwingUtilities.**invokeLater()**, just like other listener methods such as **addChangeListener()** or **addActionListener()**.

---

<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: [June 4, 2024, 1:56pm UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/16 "2024-06-04T13:56:14Z")

</div>

> [@svan](#):
>
> The only reason I use it in Processing is because I was cautioned when I posted the first demo here some time back (referenced above), and it seems pretty well accepted that Swing is not ‘thread safe’, whatever that entails.

As I’ve mentioned before as well, the safest way to deal w/ Swing components is by delegating such code to its EDT thread.

However, for simple GUI building, Processing has a long history of being able to do that under its Animation thread in **setup()** w/o any issues.

We can also increase the odds even more by moving all the **add()** method calls to the very end of the GUI building process:

```auto
frame.add(slider); frame.add(label); frame.add(btn)
slider.repaint(); label.repaint(); btn.repaint()

```

This way, the chances of a user starting using those components too early before everything is fully in place is very slim.

Whether going safer w/ **invokeLater()** or taking the risk of keeping everything under the Animation thread in **setup()** is a personal decision.

But whatever path we take, apply it equally both on Processing’s Java Mode & py5/JPype versions.

---

<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 4, 2024, 4:03pm UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/17 "2024-06-04T16:03:09Z")

</div>

Thanks for the code on SwingUtilities; it’s a lot easier than I ever thought it would be, but that’s the ‘Python way’. Your code runs ok in Thonny. What’s up with using underscores in the actionEvents? I have seen myBtnAction(event) used, but not an underscore. The following demo is a modification of my original post to use an EventDispatchThread; I prefer to use ‘Import mode for py5’ to avoid having to use prefixes. It’s more like regular Processing code that way.

```auto
# Uses Imported mode for py5

from javax.swing import *
from java.awt import *

_wndW = 600
_wndH = 660

myColor = Color.GREEN
slider = JSlider()

def myBtnAction(event):
    global myColor
    panel = JPanel()
    myColor = JColorChooser.showDialog(panel,"Choose color",Color.GREEN)

def buildWnd():
    global slider
    slider = JSlider(JSlider.HORIZONTAL, 0, 500, 100)
    slider.setBounds(180, 20, 200, 24)
    slider.setToolTipText("size");
    frame.add(slider)
    slider.repaint()
    
    btn = JButton("Color")
    btn.setBounds(400,20,80,24)
    frame.add(btn)
    btn.repaint()
    btn.addActionListener(myBtnAction)
    
def setup():
    global frame
    size(_wndW, _wndH)
    wnd = get_surface()    
    canvas = wnd.get_native()
    frame = canvas.getFrame()
    wnd.set_title('Default Processing Window')
    canvas.setBounds(0,60,_wndW,_wndH - 60)
    SwingUtilities.invokeLater(buildWnd)

def draw():
    background(209)
    fill(myColor.getRed(), myColor.getGreen(), myColor.getBlue())
    circle(300,300,slider.getValue())

```

---

<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 4, 2024, 5:05pm UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/18 "2024-06-04T17:05:16Z")

</div>

While we’re on the subject of EDT for Swing components, do you have any insight as to why this doesn’t run? Silently fails; no error messages in Thonny. There is no py5.

```auto
import jpype
import jpype.imports

jpype.startJVM()
import java
import javax
from javax.swing import *

def buildWnd():
    print("Got to here.")
    frame = JFrame("Hello World Swing")
    print("Never gets to here.")
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
    frame.setBounds(100,100,400,400)
    frame.setVisible(True)
    print("Done.")
    
SwingUtilities.invokeLater(buildWnd)    

```

**Addendum:**  
I think it has to have two threads: a main one and EDT for Swing (but I still don’t see a window):

```auto
import jpype
import jpype.imports

jpype.startJVM()

import javax
from javax.swing import *

def buildWnd():
    print("buildWnd called.")
    
def setup():
    print("Got to here.")
    frame = javax.swing.JFrame("Swing Demo")
    frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE)
    frame.setBounds(100,100,400,400)
    frame.setVisible(True)
    print("frame =",frame)
    print("Done.")
    
    javax.swing.SwingUtilities.invokeLater(buildWnd)

if __name__ == ' __main__':
    setup()

```

**Console output:**

```auto
Got to here.
buildWnd called.
frame = javax.swing.JFrame[frame0,100,100,400x400,layout=java.awt.BorderLayout,title=Swing Demo,resizable,normal,defaultCloseOperation=EXIT_ON_CLOSE,rootPane=javax.swing.JRootPane[,0,28,400x372,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777673,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true]
Done.

```

**New Console Output:** EDT called later after indenting SwingUtilities call

```auto
Got to here.
frame = javax.swing.JFrame[frame0,100,100,400x400,layout=java.awt.BorderLayout,title=Swing Demo,resizable,normal,defaultCloseOperation=EXIT_ON_CLOSE,rootPane=javax.swing.JRootPane[,0,28,400x372,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777673,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true]
Done.
>>> buildWnd called.

```

**Addendum 2:**  
AppHelper is your friend. This runs on a Mac in Thonny editor. @GoToLoop Can you run this on your Windows system?

```auto
import jpype
import jpype.imports

jpype.startJVM()

import java
import javax
from javax.swing import *
from PyObjCTools import AppHelper

def buildWnd():
    print("buildWnd called.")
    print("frame in buildWnd =",frame)
    btn = javax.swing.JButton("Button")
    btn.setBounds(30,60,100,24)
    frame.add(btn)
    frame.setVisible(True)
    print("btn =",btn)
    print("EDT =",javax.swing.SwingUtilities.isEventDispatchThread())
    print("Done in buildWnd.")
    
def main():
    global frame

    frame = javax.swing.JFrame("Swing EDT")
    frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE)
    frame.setBounds(100,100,400,400)
    frame.setLayout(None)

    javax.swing.SwingUtilities.invokeLater(buildWnd)
    AppHelper.runEventLoop()

main()

```

**Output:**

 ![helper](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/4/c/4cc1b2ce5b35f66301eb9ea1760fc4063cf4fa59.png)

**Console output:**

```auto
buildWnd called.
frame in buildWnd = 2024-06-05 21:42:40.868 Python[40240:1751568] WARNING: Secure coding is not enabled for restorable state! Enable secure coding by implementing NSApplicationDelegate.applicationSupportsSecureRestorableState: and returning YES.
javax.swing.JFrame[frame0,100,100,400x400,invalid,hidden,layout=java.awt.BorderLayout,title=Swing EDT,resizable,normal,defaultCloseOperation=EXIT_ON_CLOSE,rootPane=javax.swing.JRootPane[,0,0,0x0,invalid,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777673,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true]
btn = javax.swing.JButton[,30,60,100x24,alignmentX=0.0,alignmentY=0.5,border=com.apple.laf.AquaButtonBorder$Dynamic@457e5465,flags=288,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=0,left=2,bottom=0,right=2],paintBorder=true,paintFocus=true,pressedIcon=,rolloverEnabled=false,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=Button,defaultCapable=true]
EDT = True
Done in buildWnd.

```

---

<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: [June 6, 2024, 5:25am UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/19 "2024-06-06T05:25:43Z")

</div>

> [@svan](#):
>
> Can you run this on your Windows system?

I don’t have package PyObjCTools installed. Also, it seems it’s MacOS-only! 🍎

I’ve replaced your AppHelper.**runEventLoop()** w/ a `while True:` loop plus time.**sleep()**, so it can run on Windows, even though the code works OK w/o the infinite loop: 🪟

```py
import jpype
import jpype.imports

from time import sleep

jpype.startJVM()

from javax.swing import JFrame, JButton, SwingUtilities

def buildWnd():
    btn = JButton("Button")
    btn.setBounds(30, 60, 100, 24)
    btn.addActionListener(lambda evt: print(evt, '\n'))

    frame.add(btn)
    frame.setVisible(True)

    print("JButton:", btn)
    print("EDT:", SwingUtilities.isEventDispatchThread(), '\n')

def main():
    global frame

    frame = JFrame("Swing EDT")
    frame.setBounds(100, 100, 400, 400)
    frame.setLayout(None)
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)

    SwingUtilities.invokeLater(buildWnd)

if __name__ == ' __main__':
    main()

    while True: # AppHelper.runEventLoop() replacement.
        try: sleep(1) # Sleep to avoid burning the CPU!
        except KeyboardInterrupt: break # Exit loop on Ctrl+C.

```

---

<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 6, 2024, 6:10am UTC](https://discourse.processing.org/t/swing-components-in-default-processing-window-py5/44482/20 "2024-06-06T06:10:07Z")

</div>

Thanks for trying; I should have known it wouldn’t work cross platform. The following should also run on Windows in addition to what you posted; it came from the JPype website but won’t run on a Mac.

```auto
import jpype
import jpype.imports

jpype.startJVM()
import java
import javax
from javax.swing import *

def createAndShowGUI():
    frame = JFrame("HelloWorldSwing")
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
    frame.setBounds(100, 100, 400, 400)
    label = JLabel("Hello World")
    frame.getContentPane().add(label)
    frame.pack()
    frame.setVisible(True)

# Start an event loop thread to handling gui events
@jpype.JImplements(java.lang.Runnable)
class Launch:
    @jpype.JOverride
    def run(self):
        createAndShowGUI()
javax.swing.SwingUtilities.invokeLater(Launch())

```

As noted above, on Windows it can be run with just the EventDispatchThread:

```auto
import jpype
import jpype.imports

jpype.startJVM()
import java
import javax
from javax.swing import *

def createAndShowGUI():
    frame = JFrame("HelloWorldSwing")
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
    frame.setBounds(100, 100, 400, 400)
    label = JLabel("Hello World")
    frame.getContentPane().add(label)
    frame.pack()
    frame.setVisible(True)

javax.swing.SwingUtilities.invokeLater(createAndShowGUI)

```

@GoToLoop Will this make it cross-platform? I think Mac would have to use PyObjc plugin for Thonny to get Cocoa framework; not sure.

```auto
import jpype
import jpype.imports

jpype.startJVM()
import java
import javax
import platform
from javax.swing import *
if(platform.system() == "Darwin"):
    from Cocoa import NSApp

def createAndShowGUI():
    frame = JFrame("HelloWorldSwing")
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
    label = JLabel("Hello World")
    frame.getContentPane().add(label)
    frame.pack()
    frame.setVisible(True)

javax.swing.SwingUtilities.invokeLater(createAndShowGUI)
print(platform.system())
if(platform.system() == "Darwin"):    
    NSApp.run()

```
