Last article showed how we could use Processing with Eclipse and Java 1.5. Heady with success, I decided to try to convert the near-trivial RandBoxes Processing demo to Jython.
Why?? Well, our group uses Blender quite a bit, and Blender uses Python as its scripting language. More generally, Python is quite popular within our scientific community.
Jython, a Python implementation using the JVM, has been surprisingly successful, having most of what we like about CPython. And its Java integration made it a natural for Processing. This presentation is a good overview.
Here’s the Java 1.4 code we’re starting with, the Processing .java file created when creating the applet above. A few notes:
public class RandBoxes extends PApplet {
int numBoxes = 1000;
ArrayList boxes = new ArrayList();
public void setup() {
size(600, 500, JAVA2D);
while(boxes.size() < numBoxes)
boxes.add(new Box(random(width), random(height)));
println("number of boxes = "+boxes.size());
}
public void draw() {
background(128);
for (int i = 0; i < boxes.size(); i++)
((Box) boxes.get(i)).step();
if (frameCount%10==0)
println("frameRate="+frameRate+" frameCount="+frameCount);
}
class Box {
int c = color(255, 255, 0);
float x, y;
Box(float x, float y) {
this.x = x;
this.y = y;
}
public void step() {
x = max(min(x+random(-1, 1), width), 0);
y = max(min(y+random(-1, 1), height), 0);
paint();
}
public void paint() {
noStroke();
fill(c);
rect(x-2, y-2, 5, 5);
}
}
}
Here’s the Jython I eventually came up with. Note this is not “pythonic” yet, but at least runs. Goals:
To run,
export CLASSPATH=~/local/processing/lib/core.jar:.
then put this in any file other than RandBoxes.py (see notes). I use RandBoxesTest.py :
from javax.swing import JFrame
from processing.core import PApplet
from random import uniform
winWidth=600
winHeight=500
numBoxes = 1000
boxes = []
class RandBoxes (PApplet):
def __init__(self):
pass
def setup(self):
self.size(winWidth, winHeight, self.JAVA2D)
while len(boxes)<numBoxes:
boxes.append(\
Box(self, uniform(0,winWidth),uniform(0,winHeight)))
print "number of boxes = %d" % len(boxes)
# rqd due to PApplet's using frameRate and frameRate(n) etc.
def getField(self, name):
return self.class.superclass.getDeclaredField(name).get(self)
def draw(self):
self.background(128)
for b in boxes: b.step()
if self.frameCount % 10 == 0:
print "frameRate=%f frameCount=%i" % \
(self.getField('frameRate'), self.frameCount)
class Box(object):
def __init__(self, p, x, y):
self.p = p
self.x = x
self.y = y
self.c = p.color(255,255,0)
def step(self):
self.x = max(min(self.x+uniform(-1,1),winWidth),0)
self.y = max(min(self.y+uniform(-1,1),winHeight),0)
self.paint()
def paint(self):
self.p.noStroke()
self.p.fill(self.c)
self.p.rect(self.x-2,self.y-2,5,5)
if __name__ == '__main__':
frame = JFrame(title="Processing",
resizable = 0,
defaultCloseOperation=JFrame.EXIT_ON_CLOSE)
panel = RandBoxes()
frame.add(panel)
panel.init()
while panel.defaultSize and not panel.finished:
pass
frame.pack()
frame.visible = 1
To build the Applet, I used this jythonc command:
jythonc -J-g:none --core --deep --jar RandBoxes.jar RandBoxesTest.py
The applet tag looks like:
<applet code="RandBoxesTest$RandBoxes"
archive="RandBoxes.jar,core.jar"
width=600 height=500>
</applet>
The Applet, and similar links, are here:
import processing.core.*;
public class PAppletProxy extends PApplet {
public float getFrameRate() {
return frameRate;
}
}