Swing JSliders
From Processing
| Versions: | 1.0+ |
| Contributors: | irag |
| Started: | 2008-09-20 |
AWT and Swing components should not be used within Processing sketches.
A hack around this is to use Processing within a standard Java application. (Ooh, aahh!)
The PApplet, among its many other sexy capabilities, is a standard Java component, meaning that it can be integrated into a Java AWT or Swing application. This is very cool, as it allows you to utilize sophisticated GUI elements while still using the Processing commands you've come to love - all within the same app.
In this example, a springy kite-like object is controlled by a set of Swing JSliders. The kite may be dragged around the window - //weeeee!//
Contents |
Compiling/Running Instructions
The application has 2 main classes (KiteController.java and Kite.java), as well as a couple of inner classes you don't need to worry about. In addition, you'll need Processing's core.jar. You can get a copy of core.jar from within the lib directory of your Processing application directory. The only potentially tricky issue is dealing with Java classpath joy. When compiling/running you'll need to show java where it can find PApplet.java, which is within core.jar. You'll also need to include the current directory in the path, which is **.** .
OS X
- Place Kite.java within the package structure com/iragreenberg (so it's relative address will be com/iragreenberg/Kite.java). KiteController.java and core.jar should be next to the com directory.
- Type javac -cp .:core.jar KiteController.java
- Type java -cp .:core.jar KiteController
Windows
Switch the :'s in the class path with ;'s
Source Code
/** swing sliders taken from http://wiki.processing.org/index.php?title=Swing_JSliders_with_Processing @author Ira Greenberg Put ''Kite.java'' and KiteController.java in their own files and follow instructions outlined above. */ /******************************* KiteController class *******************************/ import com.iragreenberg.Kite; import java.awt.*; import javax.swing.event.*; import javax.swing.*; public class KiteController extends JPanel { private int w = 600, h = 422; private Kite kite; // constructor public KiteController() { setBackground(new Color(180, 180, 220)); /* create 2 pane across layout left pane holds processing PApplet right pane holds user widgets */ setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS)); // Instantiate Kite object kite = new Kite(400, 400); // right tools pane JPanel rtPanel = new JPanel(); rtPanel.setOpaque(false); rtPanel.setLayout(new BoxLayout(rtPanel, BoxLayout.PAGE_AXIS)); JLabel jl = new JLabel(" Drag the Kite String"); // kite radius slider JSlider js0 = new JSlider(JSlider.HORIZONTAL, 10, 100, 40); js0.setBorder(BorderFactory.createTitledBorder("Kite Radius")); js0.setMajorTickSpacing(30); js0.setMinorTickSpacing(4); js0.setPaintTicks(true); js0.setPaintLabels(true); // handle js0 change events js0.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent evt) { JSlider slider = (JSlider)evt.getSource(); if (!slider.getValueIsAdjusting()) { kite.setRadius(slider.getValue()); } } } ); // kite sides slider JSlider js1 = new JSlider(JSlider.HORIZONTAL, 3, 63, 4); js1.setBorder(BorderFactory.createTitledBorder("Kite Sides")); js1.setMajorTickSpacing(12); js1.setMinorTickSpacing(1); js1.setPaintTicks(true); js1.setPaintLabels(true); // handle js1 change events js1.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent evt) { JSlider slider = (JSlider)evt.getSource(); if (!slider.getValueIsAdjusting()) { kite.setFeetCount(slider.getValue()); } } } ); // spring speed slider JSlider js2 = new JSlider(JSlider.HORIZONTAL, 1, 10, 5); js2.setBorder(BorderFactory.createTitledBorder("Spring Speed")); js2.setMajorTickSpacing(3); js2.setMinorTickSpacing(1); js2.setPaintTicks(true); js2.setPaintLabels(true); // handle js2 change events js2.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent evt) { JSlider slider = (JSlider)evt.getSource(); if (!slider.getValueIsAdjusting()) { kite.setSpringSpeed(slider.getValue()/20.0f); } } } ); // spring damping slider JSlider js3 = new JSlider(JSlider.HORIZONTAL, 1, 10, 4); js3.setBorder(BorderFactory.createTitledBorder("Spring Damping")); js3.setMajorTickSpacing(1); js3.setMinorTickSpacing(1); js3.setPaintTicks(true); js3.setPaintLabels(true); // handle js3 change events js3.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent evt) { JSlider slider = (JSlider)evt.getSource(); if (!slider.getValueIsAdjusting()) { kite.setSpringDamping(1.0f - slider.getValue()/30.0f); } } } ); // assemble tools pane rtPanel.add(jl); rtPanel.add(Box.createRigidArea(new Dimension(0,10))); rtPanel.add(js0); rtPanel.add(Box.createRigidArea(new Dimension(0,8))); rtPanel.add(js1); rtPanel.add(Box.createRigidArea(new Dimension(0,8))); rtPanel.add(js2); rtPanel.add(Box.createRigidArea(new Dimension(0,8))); rtPanel.add(js3); // Next comment taken directly from PApplet class: /* "...ensures that the animation thread is started and that other internal variables are properly set."*/ kite.init(); // add panes to larger JPanel add(kite); // create some space between panes add(Box.createRigidArea(new Dimension(4,0))); add(rtPanel); // add a little margin on right of panel add(Box.createRigidArea(new Dimension(4,0))); } // create external JFrame private static void createGUI() { // create new JFrame JFrame jf = new JFrame("Kite Swing Application"); // this allows program to exit jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // You add things to the contentPane in a JFrame jf.getContentPane().add(new KiteController()); // keep window from being resized jf.setResizable(false); // size frame jf.pack(); // make frame visible jf.setVisible(true); } public static void main(String[] args) { // threadsafe way to create a Swing GUI javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createGUI(); } } ); } } /******************************* Kite class *******************************/ /* By extending PApplet you can use your sweet old P5 calls in a regular Java App. Pretty nice indeed! */ package com.iragreenberg; import processing.core.*; import java.awt.*; public class Kite extends PApplet { // instance properties private Point2D dummy; private Vect2D dummyVel; private int feetCount = 4; private Point2D[] feet = new Point2D[feetCount]; private Vect2D[] feetDelta = new Vect2D[feetCount]; private Vect2D[] feetVel = new Vect2D[feetCount]; private Vect2D[] feetAccel = new Vect2D[feetCount]; private float botRadius = 45.0f; private float[] springSpeed = new float[feetCount]; private float springSpdMin = .05f, springSpdMax = .1f; private float damping = .9f; private Point2D lead; private Vect2D leadVel; private int w, h; private int stringBaseX; private int stringBaseY; private float theta = 0; // constructor public Kite(int w, int h){ this.w = w; this.h = h; } // Yes, this is the P5 setup() public void setup(){ /* account for height of frame title bar, when sizing applet. getBounds() returns a Java Rectangle object that has 4 public properties: (x, y, width and height) */ int titleBarHt = getBounds().y; size(w, h-titleBarHt); smooth(); frameRate(30); dummy = new Point2D(width/2, height/4); dummyVel = new Vect2D(3.65f, 2.0f); lead = new Point2D(width/2, height/2); leadVel = new Vect2D(.04f, .05f); stringBaseX = width/2; stringBaseY = height; // set legs with some trig for (int i=0; i<feet.length; i++){ feet[i] = new Point2D(dummy.x + cos(theta)*botRadius, dummy.y + sin(theta)*botRadius); feetDelta[i] = new Vect2D(feet[i].x-dummy.x, feet[i].y-dummy.y); feetVel[i] = new Vect2D(0, 0); feetAccel[i] = new Vect2D(0, 0); theta += TWO_PI/feet.length; springSpeed[i] = random(springSpdMin, springSpdMax); } } // A huh, this is the P5 draw() public void draw(){ background(255); drawBot(); moveBot(); } public void drawBot(){ rectMode(CENTER); fill(0); for (int i=0; i<feet.length; i++){ line(dummy.x, dummy.y, feet[i].x, feet[i].y); if (i<feet.length-1){ line(feet[i].x, feet[i].y, feet[i+1].x, feet[i+1].y); } else { line(feet[i].x, feet[i].y, feet[0].x, feet[0].y); } } line(stringBaseX, stringBaseY, dummy.x, dummy.y); if (mousePressed){ stringBaseX = mouseX; stringBaseY = mouseY; } fill(255); } public void moveBot(){ Vect2D[] feetMotionDelta = new Vect2D[feetCount]; for (int i=0; i<feet.length; i++){ feetMotionDelta[i] = new Vect2D((dummy.x-feet[i].x+ feetDelta[i].vx)*springSpeed[i], (dummy.y-feet[i].y+feetDelta[i].vy)*springSpeed[i]); feetAccel[i].vx+= feetMotionDelta[i].vx; feetAccel[i].vy+= feetMotionDelta[i].vy; feetVel[i].vx += feetAccel[i].vx; feetVel[i].vy += feetAccel[i].vy; feet[i].x = feetVel[i].vx ; feet[i].y = feetVel[i].vy ; feetAccel[i].vx *= damping; feetAccel[i].vy *= damping; float rotAng = atan2(mouseY-(height+100), mouseX-width/2); if (mousePressed){ dummy.x = mouseX + cos(rotAng)*200; dummy.y = mouseY + sin(rotAng)*200; } } } // dynamically change kite parameters public void setFeetCount(int val){ // reinitialize arrays feetCount = val; feet = new Point2D[feetCount]; feetDelta = new Vect2D[feetCount]; feetVel = new Vect2D[feetCount]; feetAccel = new Vect2D[feetCount]; springSpeed = new float[feetCount]; // reset values float theta = 0; for (int i=0; i<feet.length; i++){ feet[i] = new Point2D(dummy.x + cos(theta)*botRadius, dummy.y + sin(theta)*botRadius); feetDelta[i] = new Vect2D(feet[i].x-dummy.x, feet[i].y-dummy.y); feetVel[i] = new Vect2D(0, 0); feetAccel[i] = new Vect2D(0, 0); theta += TWO_PI/feet.length; springSpeed[i] = random(springSpdMin, springSpdMax); } } public void setRadius(int val){ botRadius = val; for (int i=0; i<feet.length; i++){ feet[i].x = dummy.x + cos(theta)*botRadius; feet[i].y = dummy.y + sin(theta)*botRadius; feetDelta[i].vx = feet[i].x-dummy.x; feetDelta[i].vy = feet[i].y-dummy.y; theta += TWO_PI/feet.length; } } public void setSpringSpeed(float val){ for (int i=0; i<feet.length; i++){ springSpeed[i] = random(springSpdMin, val); } } public void setSpringDamping(float val){ damping = val; } /* two simple inner classes to make things a little easier */ class Point2D{ float x, y; Point2D(float x, float y){ this.x = x; this.y = y; } } class Vect2D{ float vx, vy; Vect2D(float vx, float vy){ this.vx = vx; this.vy = vy; } } }