How to use swing components with Processing (3.3.6)

I tried to add swing components to my projects for a long time as you can easily construct user interfaces with swing and use them to manipulate my program. After a long time I managed to combine the two. Here is a example I wrote for my collegues (who are swing newbies).

Here is my code:

WindowsExample.pde

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

JTextField props[]=new JTextField[11];
String outputs[]=new String[props.length];
int outputsInt[]=new int[props.length];
void setup() {
  size(200, 200);
  //Sets the PApple (Processing program) to use for the Window maker. DO NOT USE IN ANOTHER CLASS!
  SwingConstructor.setPApplet(this);
  
  for (int i=0; i<props.length; i++) props[i]=new JTextField(10);
  JPanel description_added[]=new JPanel[props.length];
  
  //Joins components vertically
  description_added[0]=SwingConstructor.list_col(new JLabel("x:"), props[0]);
  description_added[1]=SwingConstructor.list_col(new JLabel("y:"), props[1]);
  description_added[2]=SwingConstructor.list_col(new JLabel("r1:"), props[2]);
  description_added[3]=SwingConstructor.list_col(new JLabel("r2:"), props[3]);
  description_added[4]=SwingConstructor.list_col(new JLabel("r:"), props[4]);
  description_added[5]=SwingConstructor.list_col(new JLabel("g:"), props[5]);
  description_added[6]=SwingConstructor.list_col(new JLabel("b:"), props[6]);
  description_added[7]=SwingConstructor.list_col(new JLabel("r:"), props[7]);
  description_added[8]=SwingConstructor.list_col(new JLabel("g:"), props[8]);
  description_added[9]=SwingConstructor.list_col(new JLabel("b:"), props[9]);
  description_added[10]=SwingConstructor.list_col(new JLabel("w:"), props[10]);
  JButton resetButton=new JButton("Reset");
  //Adds the method reset to the button
  SwingConstructor.callMethodOnClick(resetButton,"reset");
  
  //Joins components horizonaly
  JPanel prompt=SwingConstructor.list_row(new JLabel("Setting:"), description_added[0], description_added[1], description_added[2], description_added[3], 
    SwingConstructor.list_col(new JLabel("Color inside:")), description_added[4], description_added[5], description_added[6], 
    SwingConstructor.list_col(new JLabel("Outside line:")), description_added[7], description_added[8], description_added[9], description_added[10],
    resetButton);
  
  //Fiddling about with the dimensions
  Dimension size_prompt=prompt.getPreferredSize();
  size_prompt.width=150;
  prompt.setPreferredSize(size_prompt);
  
  //Adds the contents of the processing window to the right (East)
  JFrame mainWindow=SwingConstructor.merge(SwingConstructor.scrollable(prompt,190,height), "East");
  mainWindow.setVisible(true);
  mainWindow.setTitle("Example");
  reset();
}
void draw() {
  background(255);
  updateOutputsInt();
  strokeWeight(outputsInt[10]);
  stroke(outputsInt[7], outputsInt[8], outputsInt[9]);
  fill(outputsInt[4], outputsInt[5], outputsInt[6]);
  ellipse(outputsInt[0], outputsInt[1], outputsInt[2], outputsInt[3]);
}

void reset() {
  props[0].setText(""+(width/2));
  props[1].setText(""+(height/2));
  props[2].setText("30");
  props[3].setText("20");
  props[4].setText("255");
  props[5].setText("255");
  props[6].setText("255");
  props[7].setText("0");
  props[8].setText("0");
  props[9].setText("0");
  props[10].setText("1");
}
void updateOutputs() {
  for (int i=0; i<props.length; i++) outputs[i]=props[i].getText();
}
void updateOutputsInt() {
  updateOutputs();
  for (int i=0; i<props.length; i++) outputsInt[i]=int(outputs[i]);
}

SwingConstructor.java

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

import javax.swing.*;
import java.lang.reflect.*;
import processing.core.PApplet;
class SwingConstructor {
  public static PApplet genericPapplet;
  public static void setPApplet(PApplet p) {
    genericPapplet=p;
  }
  public static int offset=15;
  public static ActionListener callMethodOnClick(String method) {
    final String parse=method;
    return new ActionListener() {

      @Override
        public void actionPerformed(ActionEvent e) {

        try {
          Method functions=genericPapplet.getClass().getMethod(parse, new Class[]{});
          functions.invoke(genericPapplet, new Object[]{});
        }
        catch(Exception exc) {
        }
      }
    
  };
}
public static void callMethodOnClick(AbstractButton button, String method) {
  button.addActionListener(callMethodOnClick(method));
}
public static JPanel list_col(Container... c) {
  JPanel ret=new JPanel();
  //ret.setLayout(new BoxLayout(ret, BoxLayout.X_AXIS));
  int w=0;
  int h=0;
  for (Container i : c) {
    ret.add(i);
    Dimension d=i.getPreferredSize();
    w+=d.width+offset;
    h=Math.max(h, d.height);
  }
  h=offset;
  ret.setPreferredSize(new Dimension(w, h));
  return ret;
}
public static JPanel list_row(Container... c) {
  JPanel ret=new JPanel();
  ret.setLayout(new BoxLayout(ret, BoxLayout.Y_AXIS));
  int w=0;
  int h=0;
  for (Container i : c) {
    ret.add(i);
    Dimension d=i.getPreferredSize();
    h+=d.height+offset;
    w=Math.max(h, d.width);
  }
  ret.setPreferredSize(new Dimension(w, h));
  return ret;
}
public static JScrollPane scrollable(Container content) {

  return new JScrollPane(content);
}
public static JScrollPane scrollable(Container content, int w, int h) {
  JScrollPane ret=new JScrollPane(content);
  ret.setPreferredSize(new Dimension(w, h));
  return ret;
}

public static JFrame merge(Container content, String where) {
  PApplet programm=genericPapplet;
  //Create new Window with Swing components
  JFrame window=new JFrame();
  window.add(content);

  //Transfer the Window
  JFrame  mainFrame=(JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas)programm.getSurface().getNative()).getFrame();
  Container processing_content=mainFrame.getContentPane();
  processing_content.setPreferredSize(new Dimension(programm.width, programm.height));
  window.add(processing_content, where);

  //Get rid of evidence
  mainFrame.setVisible(false);
  window.setSize(new Dimension(programm.width+content.getPreferredSize().width, Math.max(programm.height, content.getPreferredSize().height)));
  window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  return window;
}
}

The SwingConstructor class is a class I defined in a library of mine thats why I made a .java file.

Hope I could help someone with that!

2 Likes

Sorry, but what is the “question” part…?

Also, you may want to look into libraries such as ControlP5 and UiBooster (or create something similar / better than them, you seem to be pretty good at what you do, :)!)

1 Like

It was moved into Coding Questions after I posted it into another category…

1 Like

@NumericPrime / @NumericPrime

This is the source code I was looking for.

Do you have an example file or something similar to scrolling?
If you share it, it will be of great help to me.

I have a question.

  1. How to modify the starting coordinate value of the scroll area?

  2. How do I edit the width and height of the scroll area?

With (1) do you mean the starting position of the scroller?

What do you mean by scroll area in (2)? Do you mean the size of the object to be srolled through or do you mean the size of the scroll-pane?

If you want you can try out SwingHelper from the contributions-manager wich is a library developed by me, specialized to use swing components with processing.

Note: The method showcased here only works when using JAVA2D as renderer.

1 Like

@NumericPrime

java.lang.IllegalStateException: Buffers have not been created
	at sun.awt.windows.WComponentPeer.getBackBuffer(WComponentPeer.java:1018)
	at java.awt.Component$FlipBufferStrategy.getBackBuffer(Component.java:4065)
	at java.awt.Component$FlipBufferStrategy.updateInternalBuffers(Component.java:4050)
	at java.awt.Component$FlipBufferStrategy.revalidate(Component.java:4165)
	at java.awt.Component$FlipBufferStrategy.revalidate(Component.java:4147)
	at java.awt.Component$FlipBufferStrategy.getDrawGraphics(Component.java:4139)
	at processing.awt.PSurfaceAWT.render(PSurfaceAWT.java:298)
	at processing.awt.PSurfaceAWT$SmoothCanvas.paint(PSurfaceAWT.java:250)
	at sun.awt.RepaintArea.paintComponent(RepaintArea.java:264)
	at sun.awt.RepaintArea.paint(RepaintArea.java:240)
	at sun.awt.windows.WComponentPeer.handleEvent(WComponentPeer.java:358)
	at java.awt.Component.dispatchEventImpl(Component.java:4965)
	at java.awt.Component.dispatchEvent(Component.java:4711)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
	at java.awt.EventQueue.access$500(EventQueue.java:97)
	at java.awt.EventQueue$3.run(EventQueue.java:709)
	at java.awt.EventQueue$3.run(EventQueue.java:703)
	at java.security.AccessController.doPrivileged(Native Method)
	at

On my laptop, the code worked fine.

However, the following error occurs on PC.
Do you have any idea why?

When I search on Google, this seems to be a problem, but I don’t know how to set it up.

This issue seems to arise when using multiple screen and the solution can’t be implemented with processing. However since processing creates a new window without the issues arising.
I have made another version of the SwingConstructor that might fix that issue:

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

import javax.swing.*;
import java.lang.reflect.*;
import processing.core.PApplet;
class SwingConstructor {
  public static PApplet genericPapplet;
  public static void setPApplet(PApplet p) {
    genericPapplet=p;
  }
  public static int offset=15;
  public static ActionListener callMethodOnClick(String method) {
    final String parse=method;
    return new ActionListener() {

      @Override
        public void actionPerformed(ActionEvent e) {

        try {
          Method functions=genericPapplet.getClass().getMethod(parse, new Class[]{});
          functions.invoke(genericPapplet, new Object[]{});
        }
        catch(Exception exc) {
        }
      }
    };
  }
  public static void callMethodOnClick(AbstractButton button, String method) {
    button.addActionListener(callMethodOnClick(method));
  }
  public static JPanel list_col(Container... c) {
    JPanel ret=new JPanel();
    //ret.setLayout(new BoxLayout(ret, BoxLayout.X_AXIS));
    int w=0;
    int h=0;
    for (Container i : c) {
      ret.add(i);
      Dimension d=i.getPreferredSize();
      w+=d.width+offset;
      h=Math.max(h, d.height);
    }
    h=offset;
    ret.setPreferredSize(new Dimension(w, h));
    return ret;
  }
  public static JPanel list_row(Container... c) {
    JPanel ret=new JPanel();
    ret.setLayout(new BoxLayout(ret, BoxLayout.Y_AXIS));
    int w=0;
    int h=0;
    for (Container i : c) {
      ret.add(i);
      Dimension d=i.getPreferredSize();
      h+=d.height+offset;
      w=Math.max(h, d.width);
    }
    ret.setPreferredSize(new Dimension(w, h));
    return ret;
  }
  public static JScrollPane scrollable(Container content) {

    return new JScrollPane(content);
  }
  public static JScrollPane scrollable(Container content, int w, int h) {
    JScrollPane ret=new JScrollPane(content);
    ret.setPreferredSize(new Dimension(w, h));
    return ret;
  }

  public static JFrame merge(Container content, String where) {
    PApplet programm=genericPapplet;
    //Transfer the Window
    JFrame  mainFrame=(JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas)programm.getSurface().getNative()).getFrame();
    Container processing_content=mainFrame.getContentPane();
    processing_content.setPreferredSize(new Dimension(programm.width, programm.height));
    JPanel doneContent=new JPanel();
    doneContent.setLayout(new BorderLayout());
    doneContent.add(processing_content, where);
    doneContent.add(content);
    //Get rid of evidence
    mainFrame.setVisible(false);
    mainFrame.setContentPane(doneContent);
    mainFrame.setSize(new Dimension(programm.width+content.getPreferredSize().width, Math.max(programm.height, content.getPreferredSize().height)));

    return mainFrame;
  }
}

1 Like

Thanks @NumericPrime ! This really helped me out.

In case anyone is trying to do this in Java, here are updated versions of the file that compile in Java (I added some niceties around error handing).

Example.java

package ProcessingSwingTest;

import java.awt.*;
//import java.awt.event.*;
import javax.swing.*;
import processing.core.PApplet;

public class Example extends PApplet {

    public JTextField props[] = new JTextField[11];
    public String outputs[] = new String[props.length];
    public int outputsInt[] = new int[props.length];

    public void settings() {
        size(200, 200);
    }

    public void setup() {
        // Sets the PApple (Processing program) to use for the Window maker. DO NOT USE
        // IN ANOTHER CLASS!
        SwingConstructor.setPApplet(this);

        for (int i = 0; i < props.length; i++) {
            props[i] = new JTextField(10);
        }

        JPanel description_added[] = new JPanel[props.length];

        // Joins components vertically
        description_added[0] = SwingConstructor.list_col(new JLabel("x:"), props[0]);
        description_added[1] = SwingConstructor.list_col(new JLabel("y:"), props[1]);
        description_added[2] = SwingConstructor.list_col(new JLabel("r1:"), props[2]);
        description_added[3] = SwingConstructor.list_col(new JLabel("r2:"), props[3]);
        description_added[4] = SwingConstructor.list_col(new JLabel("r:"), props[4]);
        description_added[5] = SwingConstructor.list_col(new JLabel("g:"), props[5]);
        description_added[6] = SwingConstructor.list_col(new JLabel("b:"), props[6]);
        description_added[7] = SwingConstructor.list_col(new JLabel("r:"), props[7]);
        description_added[8] = SwingConstructor.list_col(new JLabel("g:"), props[8]);
        description_added[9] = SwingConstructor.list_col(new JLabel("b:"), props[9]);
        description_added[10] = SwingConstructor.list_col(new JLabel("w:"), props[10]);
        JButton resetButton = new JButton("Reset");
        // Adds the method reset to the button
        SwingConstructor.callMethodOnClick(resetButton, "reset");

        // Joins components horizonaly
        JPanel prompt = SwingConstructor.list_row(
                new JLabel("Setting:"),
                description_added[0],
                description_added[1],
                description_added[2],
                description_added[3],
                SwingConstructor.list_col(new JLabel("Color inside:")),
                description_added[4],
                description_added[5],
                description_added[6],
                SwingConstructor.list_col(new JLabel("Outside line:")),
                description_added[7],
                description_added[8],
                description_added[9],
                description_added[10],
                resetButton);

        // Fiddling about with the dimensions
        Dimension size_prompt = prompt.getPreferredSize();
        size_prompt.width = 150;
        prompt.setPreferredSize(size_prompt);

        // Adds the contents of the processing window to the right (East)
        JFrame mainWindow = SwingConstructor.merge(
                SwingConstructor.scrollable(prompt, 190, height), "East");

        mainWindow.setVisible(true);
        mainWindow.setTitle("Example");
        reset();
    }

    public void draw() {
        background(255);
        updateOutputsInt();
        strokeWeight(outputsInt[10]);
        stroke(outputsInt[7], outputsInt[8], outputsInt[9]);
        fill(outputsInt[4], outputsInt[5], outputsInt[6]);
        ellipse(outputsInt[0], outputsInt[1], outputsInt[2], outputsInt[3]);
    }

    public void reset() {
        props[0].setText("" + (width / 2));
        props[1].setText("" + (height / 2));
        props[2].setText("30");
        props[3].setText("20");
        props[4].setText("255");
        props[5].setText("255");
        props[6].setText("255");
        props[7].setText("0");
        props[8].setText("0");
        props[9].setText("0");
        props[10].setText("1");
    }

    public void updateOutputsInt() {
        // check whether any output has changed
        for (int i = 0; i < props.length; i++) {
            if (outputs[i] == null || !(outputs[i].equals(props[i].getText()))) {
                outputs[i] = props[i].getText();
                try {
                    outputsInt[i] = Integer.parseInt(outputs[i]);
                } catch (java.lang.NumberFormatException e) {
                    System.out.println("Can't parse input as integer: " + "\"" + outputs[i] + "\"");
                }
            }
        }
    }
}

ExampleMain.java

package ProcessingSwingTest;

import processing.core.PApplet;

public class ExampleMain {
    public static void main(String[] args){
        String[] processingArgs = {"Example"};
		Example mySketch = new Example();
		PApplet.runSketch(processingArgs, mySketch);
    }
}

SwingConstructor.java

package ProcessingSwingTest;
//from: https://discourse.processing.org/t/how-to-use-swing-components-with-processing-3-3-6/36219

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

import javax.swing.*;
import java.lang.reflect.*;
import processing.core.PApplet;

class SwingConstructor {
    public static PApplet genericPapplet;

    public static void setPApplet(PApplet p) {
        genericPapplet = p;
    }

    public static int offset = 15;

    public static ActionListener callMethodOnClick(String method) {
        final String parse = method;
        return new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                try {
                    Method functions = genericPapplet.getClass().getMethod(parse, new Class[] {});
                    functions.invoke(genericPapplet, new Object[] {});
                } catch (Exception exc) {
                }
            }
        };
    }

    public static void callMethodOnClick(AbstractButton button, String method) {
        button.addActionListener(callMethodOnClick(method));
    }

    public static JPanel list_col(Container... c) {
        JPanel ret = new JPanel();
        // ret.setLayout(new BoxLayout(ret, BoxLayout.X_AXIS));
        int w = 0;
        int h = 0;
        for (Container i : c) {
            ret.add(i);
            Dimension d = i.getPreferredSize();
            w += d.width + offset;
            h = Math.max(h, d.height);
        }
        h = offset;
        ret.setPreferredSize(new Dimension(w, h));
        return ret;
    }

    public static JPanel list_row(Container... c) {
        JPanel ret = new JPanel();
        ret.setLayout(new BoxLayout(ret, BoxLayout.Y_AXIS));
        int w = 0;
        int h = 0;
        for (Container i : c) {
            ret.add(i);
            Dimension d = i.getPreferredSize();
            h += d.height + offset;
            w = Math.max(h, d.width);
        }
        ret.setPreferredSize(new Dimension(w, h));
        return ret;
    }

    public static JScrollPane scrollable(Container content) {
        return new JScrollPane(content);
    }

    public static JScrollPane scrollable(Container content, int w, int h) {
        JScrollPane ret = new JScrollPane(content);
        ret.setPreferredSize(new Dimension(w, h));
        return ret;
    }

    public static JFrame merge(Container content, String where) {
        PApplet programm = genericPapplet;
        // Create new Window with Swing components
        JFrame window = new JFrame();
        window.add(content);

        // Transfer the Window
        JFrame mainFrame = (JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas) programm.getSurface().getNative())
                .getFrame();
        Container processing_content = mainFrame.getContentPane();
        processing_content.setPreferredSize(new Dimension(programm.width, programm.height));
        window.add(processing_content, where);

        // Get rid of evidence
        mainFrame.setVisible(false);
        window.setSize(new Dimension(programm.width + content.getPreferredSize().width,
                Math.max(programm.height, content.getPreferredSize().height)));
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        return window;
    }
}
2 Likes