Swing JSliders

From Processing

Jump to: navigation, search
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

  1. 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.
  2. Type javac -cp .:core.jar KiteController.java
  3. 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;
    }
  }
}

Downloads

Related Links

http://processing.org

Personal tools