Guide(s): Interesting methods to implement in your sketch

Over the years I work with processing I learned a few useful tricks to help me at points where Processing seems to hit it’s limits. I want to share a few of these tricks with you:

Save current state of the sketch If you are working on e.g. a game and you wish to have save states you often have to make some methods that try to convert your data into Strings and back. Updating them can be quite anoying so it might be better to have a approach you put down once and never have to worry about again. For that exact purpose I have these two methods:

//saves the data
void saveData(String relPath) {
  Object e=this;
  //get all non-transient fields
  HashMap<String, Object> ntf=new HashMap();
  java.lang.reflect.Field[] field_=e.getClass().getDeclaredFields();
  try {
    for (int i=0; i<field_.length; i++) {
      field_[i].setAccessible(true);
      if (!java.lang.reflect.Modifier.isTransient(field_[i].getModifiers())) 
   ntf.put(field_[i].getName(), field_[i].get(e));
    }
  } 
  catch (Exception ex) {
    ex.printStackTrace();
  }
  //serializes the hash-map
  try {
    saveStrings(sketchPath(relPath), new String[]{});
    java.io.FileOutputStream fileout=new java.io.FileOutputStream(sketchPath(relPath));
    java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(fileout);
    out.writeObject(ntf);
    out.close();
  }
  catch(IOException ex) {
    ex.printStackTrace();
  }
}

//loads the data
void loadData(String relPath) {
  //load HashMap from file
  HashMap<String, Object> r=new HashMap();
  try {
    java.io.FileInputStream fileout=new java.io.FileInputStream(sketchPath(relPath));
    java.io.ObjectInputStream out=new java.io.ObjectInputStream(fileout);
    r=(HashMap<String, Object>) out.readObject();
    out.close();
    
    //Load contents of the HashMap into the sketch
    Object o=this;
    java.lang.reflect.Field[] field_=o.getClass().getDeclaredFields();
    for (int i=0; i<field_.length; i++) {
      try {
        field_[i].setAccessible(true);
        //load contents only in non-transient fields
        if (!java.lang.reflect.Modifier.isTransient(field_[i].getModifiers())) field_[i].set(o, r.get(field_[i].getName()));
      }
      catch (Exception ex) {
        ex.printStackTrace();
      }
    }
  }
  catch(IOException e) {
    e.printStackTrace();
  } 
  catch (ClassNotFoundException e) {
    e.printStackTrace();
  }
}
Example

Each field you don’t want to save must be marked with the transient keyword!


int x=(int) random(0,10);
int y=(int) random(0,10);
transient int z=(int) random(0,10);
void setup() {
}
void draw() {
  println(x, y, z);
}
void keyPressed() {
  if (key=='s') saveData("data/data.txt");
  if (key=='l') loadData("data/data.txt");
}



void saveData(String relPath) {
  Object e=this;
  //get all non-transient fields
  HashMap<String, Object> ntf=new HashMap();
  java.lang.reflect.Field[] field_=e.getClass().getDeclaredFields();
  try {
    for (int i=0; i<field_.length; i++) {
      field_[i].setAccessible(true);
      if (!java.lang.reflect.Modifier.isTransient(field_[i].getModifiers())) ntf.put(field_[i].getName(), field_[i].get(e));
    }
  } 
  catch (Exception ex) {
    ex.printStackTrace();
  }
  //serializes the hash-map
  try {
    saveStrings(sketchPath(relPath), new String[]{});
    java.io.FileOutputStream fileout=new java.io.FileOutputStream(sketchPath(relPath));
    java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(fileout);
    out.writeObject(ntf);
    out.close();
  }
  catch(IOException ex) {
    ex.printStackTrace();
  }
}
void loadData(String relPath) {
  //load HashMap from file
  HashMap<String, Object> r=new HashMap();
  try {
    java.io.FileInputStream fileout=new java.io.FileInputStream(sketchPath(relPath));
    java.io.ObjectInputStream out=new java.io.ObjectInputStream(fileout);
    r=(HashMap<String, Object>) out.readObject();
    out.close();
    
    //Load contents of the HashMap into the sketch
    Object o=this;
    java.lang.reflect.Field[] field_=o.getClass().getDeclaredFields();
    for (int i=0; i<field_.length; i++) {
      try {
        field_[i].setAccessible(true);
        //load contents only in non-transient fields
        if (!java.lang.reflect.Modifier.isTransient(field_[i].getModifiers())) field_[i].set(o, r.get(field_[i].getName()));
      }
      catch (Exception ex) {
        ex.printStackTrace();
      }
    }
  }
  catch(IOException e) {
    e.printStackTrace();
  } 
  catch (ClassNotFoundException e) {
    e.printStackTrace();
  }
}

Call methods using Strings This is actually commonly used with vanilla java. The great thing is if you need to assign strings to certain methods you can use this methods instead of switch/case
Object call(String method) {
  try {
    //uses reflection to find and invoke the method
    java.lang.reflect.Method functions=this.getClass().getMethod(method, new Class[]{});
    functions.setAccessible(true);
    return functions.invoke(this, new Object[]{});
  }
  catch(Exception e) {
    e.printStackTrace();
    return null;
  }
}
Object call(String method, Object... input) {
  Class[] classes=new Class[input.length];
  for (int i=0; i<classes.length; i++) classes[i]=input[i].getClass();
  //searching for methods with a certain input differentiates bettween primitives and Objects
  //so all combinations must be checked beginning with the "all primitives"-variant
  boolean iter[]=new boolean[classes.length+1];
  for (boolean n : iter) n=false;
  while (!iter[iter.length-1]) {
    Class[] current=new Class[classes.length];
    for (int i=0; i<classes.length; i++)if (!iter[i]) {
      if (classes[i]==(Integer.class)) current[i]=int.class;
      else if (classes[i]==Float.class) current[i]=float.class;
      else if (classes[i]==Long.class) current[i]=long.class;
      else if (classes[i]==Short.class) current[i]=short.class;
      else if (classes[i]==Double.class) current[i]=double.class;
      else if (classes[i]==Boolean.class) current[i]=boolean.class;
      else current[i]=classes[i];
    } else current[i]=classes[i];
    try {
      java.lang.reflect.Method functions=this.getClass().getMethod(method, current);
      functions.setAccessible(true);
      return functions.invoke(this, input);
    }
    catch(Exception e) {
    }

    boolean stack=iter[0];
    iter[0]=!iter[0];
    for (int i=1; i<iter.length&&stack; i++) {
      stack=iter[i];
      iter[i]=!iter[i];
    }
  }
  return null;
}

The great thing about this is also that you are able to call private methods from libraries/.java tabs.

Example
void setup() {
}
void draw() {
  //invoke the first method
  call("method1");
  
  //invoke the second method with arguments
  call("method2",1,3);
}

void method1(){
println("test");
}
void method2(int x,int y){
println(x,y);
}

Object call(String method) {
  try {
    //uses reflection to find and invoke the method
    java.lang.reflect.Method functions=this.getClass().getMethod(method, new Class[]{});
    functions.setAccessible(true);
    return functions.invoke(this, new Object[]{});
  }
  catch(Exception e) {
    e.printStackTrace();
    return null;
  }
}
Object call(String method, Object... input) {
  Class[] classes=new Class[input.length];
  for (int i=0; i<classes.length; i++) classes[i]=input[i].getClass();
  //searching for methods with a certain input differentiates bettween primitives and Objects
  //so all combinations must be checked beginning with the "all primitives"-variant
  boolean iter[]=new boolean[classes.length+1];
  for (boolean n : iter) n=false;
  while (!iter[iter.length-1]) {
    Class[] current=new Class[classes.length];
    for (int i=0; i<classes.length; i++)if (!iter[i]) {
      if (classes[i]==(Integer.class)) current[i]=int.class;
      else if (classes[i]==Float.class) current[i]=float.class;
      else if (classes[i]==Long.class) current[i]=long.class;
      else if (classes[i]==Short.class) current[i]=short.class;
      else if (classes[i]==Double.class) current[i]=double.class;
      else if (classes[i]==Boolean.class) current[i]=boolean.class;
      else current[i]=classes[i];
    } else current[i]=classes[i];
    try {
      java.lang.reflect.Method functions=this.getClass().getMethod(method, current);
      functions.setAccessible(true);
      return functions.invoke(this, input);
    }
    catch(Exception e) {
    }

    boolean stack=iter[0];
    iter[0]=!iter[0];
    for (int i=1; i<iter.length&&stack; i++) {
      stack=iter[i];
      iter[i]=!iter[i];
    }
  }
  return null;
}

Use swing component with Processing Swing offers a neat way of creating user interfaces. However if you try to directly add them to processing you usually don't know where to add them or fail. These next methods are supposed to resolve this issue:
Add components to the side of the sketch This offers a way to add an preferbly formatted Container to the side of the sketch:
javax.swing.JFrame merge(java.awt.Container content, int w) {
  String where="East";
  if(w==RIGHT) where="West";
  PApplet programm=this;
  //Create new window with content
  javax.swing.JFrame window=new javax.swing.JFrame();
  window.add(content);

  //Transfer from Original window to new one
  javax.swing.JFrame  mainFrame=(javax.swing.JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas)programm.getSurface().getNative()).getFrame();
  java.awt.Container processing_content=mainFrame.getContentPane();
  processing_content.setPreferredSize(new java.awt.Dimension(programm.width, programm.height));
  window.add(processing_content, where);
  window.setSize(new java.awt.Dimension(programm.width+content.getPreferredSize().width, Math.max(programm.height, content.getPreferredSize().height)));


  //Hide tracess
  mainFrame.setVisible(false);
  window.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
  window.setIconImage(mainFrame.getIconImage());
  window.setName(mainFrame.getName());
  window.setVisible(true);
  return window;
}
Example
import javax.swing.*;
JTextField textF=new JTextField(10);
void setup() {
  size(300, 300);
  merge(textF, LEFT);
  fill(0);
}
void draw() {
  background(255);
  text(textF.getText(), 30, height/2);
}

javax.swing.JFrame merge(java.awt.Container content, int w) {
  String where="East";
  if(w==RIGHT) where="West";
  PApplet programm=this;
  //Create new window with content
  javax.swing.JFrame window=new javax.swing.JFrame();
  window.add(content);

  //Transfer from Original window to new one
  javax.swing.JFrame  mainFrame=(javax.swing.JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas)programm.getSurface().getNative()).getFrame();
  java.awt.Container processing_content=mainFrame.getContentPane();
  processing_content.setPreferredSize(new java.awt.Dimension(programm.width, programm.height));
  window.add(processing_content, where);
  window.setSize(new java.awt.Dimension(programm.width+content.getPreferredSize().width, Math.max(programm.height, content.getPreferredSize().height)));


  //Hide tracess
  mainFrame.setVisible(false);
  window.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
  window.setIconImage(mainFrame.getIconImage());
  window.setName(mainFrame.getName());
  window.setVisible(true);
  return window;
}

Free place swing components You might also want to place your swing-components freely. That can be done with these methods:
javax.swing.JFrame generated;
java.awt.Container processing_content;
javax.swing.JFrame newWindow() {
  PApplet programm=this;
  //Create new window with content
  javax.swing.JFrame window=new javax.swing.JFrame();
  window.getContentPane().setLayout(null);

  //Transfer from Original window to new one
  javax.swing.JFrame  mainFrame=(javax.swing.JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas)programm.getSurface().getNative()).getFrame();
  processing_content=mainFrame.getContentPane();
  processing_content.setPreferredSize(new java.awt.Dimension(programm.width, programm.height));
  processing_content.setBounds(new java.awt.Rectangle(0, 0, width, height));
  window.setSize(width, height);

  //Hide tracess
  mainFrame.setVisible(false);
  window.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
  window.setIconImage(mainFrame.getIconImage());
  window.setName(mainFrame.getName());
  window.setVisible(true);
  generated=window;
  return window;
}
void addContainer(java.awt.Container cont, int x, int y) {
  generated.add(cont, null);
  cont.setBounds(new java.awt.Rectangle(x, y, cont.getPreferredSize().width, cont.getPreferredSize().height));
  generated.add(processing_content, null);
}
void addContainer(java.awt.Container cont, int x, int y, int w, int h) {
  generated.add(cont, null);
  cont.setBounds(new java.awt.Rectangle(x, y, w, h));
  generated.add(processing_content, null);
}
void callMethodOnClick(javax.swing.AbstractButton button, final String method) {
  final PApplet ref=this;
  button.addActionListener(
    new java.awt.event.ActionListener() {
    @Override
      public void actionPerformed(java.awt.event.ActionEvent e) {
      //uses reflection to find and invoke the method
      try {
        java.lang.reflect.Method functions=ref.getClass().getMethod(method, new Class[]{});
        functions.setAccessible(true);
        functions.invoke(ref, new Object[]{});
      }
      catch(Exception ex) {
        ex.printStackTrace();
      }
    }
  }
  );
}

These methods also implement a way of easily straping a method onto a button.

Example
import javax.swing.*;
JTextField textF=new JTextField(10);
void setup() {
  size(500, 500);
  newWindow();
  JButton jb=new JButton("reset");
  addContainer(jb, 40, 40, 80, 50);
  addContainer(textF, 150, 40);
  callMethodOnClick(jb,"reset");
  fill(0);
}
void draw() {
  background(frameCount);
  text(textF.getText(), 30, height/2);
}
void reset() {
  textF.setText("");
}



javax.swing.JFrame generated;
java.awt.Container processing_content;
javax.swing.JFrame newWindow() {
  PApplet programm=this;
  //Create new window with content
  javax.swing.JFrame window=new javax.swing.JFrame();
  window.getContentPane().setLayout(null);

  //Transfer from Original window to new one
  javax.swing.JFrame  mainFrame=(javax.swing.JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas)programm.getSurface().getNative()).getFrame();
  processing_content=mainFrame.getContentPane();
  processing_content.setPreferredSize(new java.awt.Dimension(programm.width, programm.height));
  processing_content.setBounds(new java.awt.Rectangle(0, 0, width, height));
  window.setSize(width, height);

  //Hide tracess
  mainFrame.setVisible(false);
  window.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
  window.setIconImage(mainFrame.getIconImage());
  window.setName(mainFrame.getName());
  window.setVisible(true);
  generated=window;
  return window;
}
void addContainer(java.awt.Container cont, int x, int y) {
  generated.add(cont, null);
  cont.setBounds(new java.awt.Rectangle(x, y, cont.getPreferredSize().width, cont.getPreferredSize().height));
  generated.add(processing_content, null);
}
void addContainer(java.awt.Container cont, int x, int y, int w, int h) {
  generated.add(cont, null);
  cont.setBounds(new java.awt.Rectangle(x, y, w, h));
  generated.add(processing_content, null);
}
void callMethodOnClick(javax.swing.AbstractButton button, final String method) {
  final PApplet ref=this;
  button.addActionListener(
    new java.awt.event.ActionListener() {
    @Override
      public void actionPerformed(java.awt.event.ActionEvent e) {
      //uses reflection to find and invoke the method
      try {
        java.lang.reflect.Method functions=ref.getClass().getMethod(method, new Class[]{});
        functions.setAccessible(true);
        functions.invoke(ref, new Object[]{});
      }
      catch(Exception ex) {
        ex.printStackTrace();
      }
    }
  }
  );
}


Muting print/println using print/println is an essential of debugging a program can however easily hinder performance. There is however a easy way of "muting" the print command using these methods:
java.io.PrintStream outp;
void mute() {
  outp=System.out;
  System.setOut(new java.io.PrintStream(new OutputStream() {
    public void write(int arg) {
    }
  }
  ));
}
void unmute() {
  System.setOut(outp);
}
Example
void setup() {
}
void draw() {
  println(random(0, 10));
}
void keyPressed() {
  if (key=='m') {
    println("muting...");
    mute();
  }
  if (key=='u') {
    unmute();
    println("unmuted");
  }
}


java.io.PrintStream outp;
void mute() {
  outp=System.out;
  System.setOut(new java.io.PrintStream(new OutputStream() {
    public void write(int arg) {
    }
  }
  ));
}
void unmute() {
  System.setOut(outp);
}

Buildt-in refresh in classes (Deprecated) When making complicated sketches you often have classes with a paint-function. Including theses refreshs require you to often keep track of your Objects and refresh them in the draw-section. Library-makers might know the `registerMethod` method. But this doesn't work in normal processing-code. Here are the methods that can automate the refresh (please read the example):

ArrayList<Object> refs=new ArrayList();
ArrayList<String> mets=new ArrayList();
void strapMethod(String methodName, Object referenceName) {
  mets.add(methodName);
  refs.add(referenceName);
}
void runMethods() {
  for (int i=0; i<refs.size(); i++) {
    try {
      java.lang.reflect.Method m=refs.get(i).getClass().getMethod(mets.get(i), new Class[]{});
      m.setAccessible(true);
      m.invoke(refs.get(i),new Object[]{});
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
}
Example
void setup() {
  size(500, 500);
  for (int i=0; i<20; i++) new RandomCirles((int) random(0, width), (int) random(0, height));
}
void draw() {
  background(255);
  runMethods();
}
PApplet ref=this;
class RandomCirles {
  int x, y;
  RandomCirles(int x_, int y_) {
    x=x_;
    y=y_;
    strapMethod("draw",this);
  }
  void draw() {
    randWalk();
    paint();
  }
  void randWalk() {
    x+=(int) random(-2, 2);
    y+=(int) random(-2, 2);
  }
  void paint() {
    ellipse(x, y, 30, 30);
  }
}
ArrayList<Object> refs=new ArrayList();
ArrayList<String> mets=new ArrayList();
void strapMethod(String methodName, Object referenceName) {
  mets.add(methodName);
  refs.add(referenceName);
}
void runMethods() {
  for (int i=0; i<refs.size(); i++) {
    try {
      java.lang.reflect.Method m=refs.get(i).getClass().getMethod(mets.get(i), new Class[]{});
      m.setAccessible(true);
      m.invoke(refs.get(i),new Object[]{});
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
}

I hope I could provide a few interesting ways to use processing. If you have any question about these feel free to ask! I might make a reply explaining why I had to do things not as straightforward as one might assume them to be.

(Edit: after trying a few things I noticed registerMethod does work if you just declare the class public. I just make an example for registerMethod:

Example
void setup() {
  size(500, 500);
  for (int i=0; i<20; i++) new RandomCirles((int) random(0, width), (int) random(0, height));
}
void draw() {
  background(255);
}
PApplet ref=this;
public class RandomCirles {
  int x, y;
  RandomCirles(int x_, int y_) {
    x=x_;
    y=y_;
    ref.registerMethod("draw",this);
  }
  void draw() {
    randWalk();
    paint();
  }
  void randWalk() {
    x+=(int) random(-2, 2);
    y+=(int) random(-2, 2);
  }
  void paint() {
    ellipse(x, y, 30, 30);
  }
}
1 Like

A little info about why I often didn’t use the seemingly straightforward way for the methods.

  1. Why don’t I just serialize the PApplet?
    The anwer is simple: PApplet doesn’t implement java.io.Serializable and therefore can’t be serialized.

  2. Why can’t I directly serialize custom classes even if I implement Serializable?
    The reason for this is the same reason one can’t simply declare static fields in a class without declaring it final or the class static.

    When you create a new class in Processing without a .java tab you don’t actually create an indepenent new class it creates an nested inner class of the PApplet. This has the advantage that it makes using the canvas from within a custom class possible in the first place and makes formatting the code for compilation easier.

    However when try to serialize an element of a nested inner class it will try to serialize the main class wich won’t work.

  3. Why don’t I try to add the swing components to the processing window?
    I tried to add containers to the processing window for quite a long time.
    Processing however does something to it’s windows that made adding Containers quite a pain. The solution was creating a new window and add the custom content and the processing window in said window.

2 Likes