giCentre Utilities

Sketches in multiple windows

The multisketch package aims to make it as simple as possible to create multiple Processing sketches each sitting in their own window. Existing sketches can be placed in their own windows with minimal change of code. Sketches in separate windows can communicate with each other with minimal use of system resources when windows are not active or visible.

multiple sketches

Creating multiple sketches in Processing

To create multiple sketches you will then need to import the multisketch package with the line

import org.gicentre.utils.multisketch.*; 

For full details of the methods available see the multisketch API documentation. See also, the MultiSketchExample supplied in the examples folder of the giCentre utilities library.

To create a sketch in its own window, simply place the normal Processing code inside a class that extends EmbeddedSketch. The only other change required is that the first line of the draw() method contains the line super.draw(). This ensures that the animation loop of the sketch is not active when the window is minimised or hidden.

As an example, consider the following sketch to draw some moving text:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// Simple embedded sketch that can be placed in its own window. 
// Version 1.2, 18th July, 2009. 
// Author Jo Wood. 
 
public class AnotherSketch extends EmbeddedSketch 
{ 
  // ----------------------- Object variables ------------------------- 
   
  float textScale; 
   
  // ----------------------- Initialisation --------------------------- 
   
  /** Initialises the sketch ready to display some animated text. 
   */ 
  void setup() 
  { 
    size(300,300); 
    PFont font = createFont("SansSerif",24); 
    textFont(font, 24); 
    smooth(); 
    textAlign(CENTER,CENTER); 
    fill(20,120,20); 
    textScale = 0; 
  } 
 
  // ----------------------- Processing draw -------------------------- 
   
  /** Displays some text and animates a change in size. 
   */ 
  void draw() 
  { 
    super.draw();   // Should be the first line of draw(). 
    background(200,255,200); 
       
    pushMatrix(); 
     translate(width/2,height/2); 
     scale(0.1+sin(textScale),1); 
     text("Hello again",0,0); 
    popMatrix(); 
     
    textScale += 0.02; 
  } 
} 

The only differences between this code and a normal Processing sketch are in lines 5,6, 43 (wrapping of the sketch inside a class), and line 32 (ensuring drawing does not happen if window is not active).

To run the embedded sketch, it needs to be passed to a PopupWindow class inside a normal Processing sketch. For example,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import org.gicentre.utils.multisketch.*;  
 
// Simple example to show how two sketches can be created in separate windows. 
// Version 1.2, 18th July, 2009. 
// Author Jo Wood. 
 
// ----------------------- Object variables ------------------------- 
 
float rotationAngle; 
 
// ----------------------- Initialisation --------------------------- 
 
/** Sets up this sketch and adds another sketch in a separate window. 
 */ 
void setup() 
{ 
  size(300,300); 
  PFont font = createFont("Serif",32); 
  textFont(font, 32); 
  smooth(); 
  textAlign(CENTER,CENTER); 
  fill(120,20,20); 
  rotationAngle = 0; 
   
  PopupWindow win = new PopupWindow(this,new AnotherSketch()); 
  win.setVisible(true); 
} 
 
// ----------------------- Processing draw -------------------------- 
 
/** Displays some text and animates its rotation. 
 */ 
void draw() 
{ 
  background(255,200,200); 
   
  pushMatrix(); 
   translate(width/2,height/2); 
   rotate(rotationAngle); 
   text("Hello world",0,0); 
  popMatrix(); 
   
  rotationAngle += 0.01; 
} 

Running this sketch in Processing produces the two animated windows similar to those shown below.

Multiple windows sketch

Embedding Sketches in a Single Window

If you wish to have more than one sketch in the same window, you can create a SketchPanel instead of a PopupWindow. These panels can be laid out inside your sketch as you might any other Java component.

Note that if you do this, you will probably want to set noLoop() in your main Processing sketch since it does nothing other than hold the embedded sketches. By default, sketches embedded in a SketchPanel are 'inactive' meaning they will not animate. To start the sketches animating (if you need to), call setIsActive(true). The following provides a simple example laying out two embedded sketches in a single window,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import org.gicentre.utils.multisketch.*;  
 
// Simple example to show how two sketches can be embedded in a single window. 
// Version 1.2, 18th July, 2009. 
// Author Jo Wood. 
 
// ----------------------- Initialisation --------------------------- 
 
/** Places two embedded sketches inside this one. 
 */ 
void setup() 
{ 
  size(500,250); 
  setLayout(new GridLayout(0,2)); 
  noLoop(); 
     
  ASketch       sketch1 = new ASketch(); 
  AnotherSketch sketch2 = new AnotherSketch(); 
   
  SketchPanel sp1 = new SketchPanel(this,sketch1); 
  add(sp1); 
  sketch1.setIsActive(true); 
   
  SketchPanel sp2 = new SketchPanel(this,sketch2); 
  add(sp2); 
  sketch2.setIsActive(true); 
} 

Assuming you have created two embedded sketches elswhere (ASketch and AnotherSketch in this example), this might produce output as follows,

Two sketches embedded in a third

Linked Windows

Because any embedded sketches are created inside a parent sketch, getting multiple sketches to communicate with each other is easy. Simply create methods in the embedded sketch that send or receive any messages that need to be passed between sketches. Additionally, built-in variables associated with a sketch such as width and height may be addressed directly by prefixing them with the name of the EmbeddedSketch object.

The following example moves a line in the left-hand sketch in response to mouse movements, and then draws a continuation of that line in the second sketch:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import org.gicentre.utils.multisketch.*;  
 
// Example to show how sketches in separate windows can talk to each other. 
// Version 1.1, 18th July, 2009. 
// Author Jo Wood. 
 
// ----------------------- Object variables ------------------------- 
 
RightSketch rightSketch;    // The embedded sketch. 
 
// ----------------------- Initialisation --------------------------- 
 
/** Creates a separate sketch in its own window. 
 */ 
void setup() 
{ 
  size(300,300); 
  smooth(); 
  stroke(120,20,20); 
  strokeWeight(4); 
   
  rightSketch = new RightSketch(); 
  PopupWindow win = new PopupWindow(this,rightSketch); 
  win.setVisible(true); 
} 
 
// ----------------------- Processing draw -------------------------- 
 
/** Draws a line from current mouse position towards the centre of  
 * the other sketch. 
 */ 
void draw() 
{ 
  background(255,200,200); 
   
  float xOffset = width-mouseX + rightSketch.width/2.0; 
  float yOffset = rightSketch.height/2-mouseY; 
  line(mouseX,mouseY,mouseX+xOffset,mouseY+yOffset); 
  float angle = atan(yOffset/xOffset); 
  
  // Tell the other sketch to draw a line from one edge to its centre.  
  rightSketch.setLine(0,mouseY+(width-mouseX)*tan(angle)); 
} 

RightSketch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Simple embedded sketch that draws a line to the centre of the window 
// Version 1.1, 18th July, 2009. 
// Author Jo Wood. 
 
// ----------------------- Object variables ------------------------- 
 
public class RightSketch extends EmbeddedSketch 
{   
  // ---------------------- Object variables -------------------------- 
   
  float x1,y1;    // Start point of the line. 
   
  // ----------------------- Initialisation --------------------------- 
   
  void setup() 
  { 
    size(300,300); 
    smooth(); 
    stroke(20, 120,20); 
    strokeWeight(2); 
  } 
   
  // ----------------------- Processing draw -------------------------- 
   
  /** Draws a line from its current start point to the centre of the sketch. 
   */ 
  void draw() 
  { 
    super.draw();   // Should be the first line of draw(). 
    background(200,255,200); 
    line(x1,y1,width/2,height/2); 
  } 
   
  /** Sets the start point of the line. 
   */ 
  void setLine(float x1, float y1) 
  { 
    this.x1 = x1; 
    this.y1 = y1; 
  } 
} 

Example output is shown below:

Linked multiple windows sketch

Outstanding Issues

While most sketches require little modification to be embedded in their own window, there are a few exceptions that need to be dealt with differently.

Loading Files with Processing Methods

Processing methods that involve loading files from the default ./data folder will not work in an embedded sketch by default (they don't look in the correct folder). These include:

To use these methods, the embedded sketch needs to be told to look in the same folder as the main sketch. To do this, call the setParentSketch() method somewhere in your main sketch. For example if you have created an embedded sketch called embeddedSketch, you would call the following in your main sketch

embeddedSketch.setParentSketch(this); 

Calling Processing Methods Inside External Classes

If your sketch makes use of external classes (ie classes defined in their own tab window outside of any sketch), calling processing methods from within them can lead to ambiguous references to the sketch to which they apply. This is particularly the case for methods that affect the state of a sketch, such as pushMatrix(), popMatrix(), scale(), translate(), rotate(), fontSize() etc. Note this is not a problem if these methods are called from within an embedded sketch (e.g. first example above).

To overcome the problem, the sketch to which the methods are to be applied should be passed to the class that wishes to use them. This can be thought of as providing the context to the class that needs to operate within a particular sketch.