Multi-threaded Graphics_demo

I was recently forced to draw a graph from an android thread and much to my surprise it worked. I was under the impression that all drawing had to be done with draw() and, in fact, Processing documentation explicitly states:

You cannot draw to the screen from a function called by thread().

The following demo shows that it can be done, provided you use a single stroke color and minimal use of draw() for other purposes. Note that each thread has a unique timer interval.

/*
  Plots data in three rectangles ("channels") simultaneously using a different
  thread with unique timer interval for each channel. For best results, use a 
  single stroke color and minimal use of draw().  noStroke() may not be honored.   
  Suggest LANDSCAPE for tablets and PORTRAIT for smaller devices.
*/

boolean stopPlot; 

int x = 0;
int y = 0;
int y1 = 0;

int i = 0;
int j = 0;
int j1 = 0;

int m = 0;
int n = 0;
int n1 = 0;

long Timer1 = 0;
long Timer2 = 0;
long Timer3 = 0;

final int Interval_10 = 10;
final int Interval_50 = 50;
final int Interval_100 = 100;
final int Interval_1000 = 1000;

final int _stopBtnX = 30;
final int _stopBtnY = 30;
final int _stopBtnW = 150;
final int _stopBtnH = 60;

class StopBtn {
 void display(){
   fill(151,186,66,255); // background color - GREEN
   noStroke();
   rect(_stopBtnX, _stopBtnY, _stopBtnW, _stopBtnH, 15);
   fill(0); // text color
   textSize(42);
   text("Stop", _stopBtnX + 20, _stopBtnY + 15, _stopBtnW, _stopBtnH);
 }
  
 void press() {
  if(stopPlot){
   stopPlot = false;
  } else {
   stopPlot = true;
   exit();
  }
  println("stopPlot = ", stopPlot);
 }
 
}
StopBtn stopBtn;

void setup() { 
   background(0, 0, 200); // blue
   // Recommended for tablets
   orientation(LANDSCAPE);
   // Recommended for smaller devices
  // orientation(PORTRAIT);
   stopBtn = new StopBtn();   
   stopBtn.display();
   stopPlot = false;
   thread("plot1");
   thread("plot2");
   thread("plot3");
  
  colorMode(HSB, 360, 100, 100);
  
  // plot1 rectangle
   noStroke();
   fill(166,118,60);
   rect(0,height - 350, width, 350);
   
  // plot2 rectangle
   noStroke();
   fill(218);   
   rect(0,height - 700, width, 350);
   
   // plot3 rectangle  
   noStroke();
   fill(180, 42, 50);
   rect(0, height - 1050, width, 350);  
   
} 

void draw() { 
} 

void plot3() {
 while (!stopPlot) { 
  if (millis() >= Timer3) {
     Timer3 += Interval_50; 
      n += 8;
      if (n > 256) {n = 0;}
      stroke(255);
      strokeWeight(6);
      line(m, height - 750 - n, m++, height - 750 - n1);
      n1 = n;
      m += 5;
      if (m > width) {
      m = 0;
      noStroke();
      fill(180, 42, 50);
      rect(0,height - 1050, width, 350);
      }     
    }
   }
 } 

void plot2() {
 while (!stopPlot) { 
  if (millis() >= Timer2) {
     Timer2 += Interval_100; 
      j += 8;
      if (j > 256) {j = 0;}
      stroke(255);
      strokeWeight(6);
      line(i, height - 400 - j, i++, height - 400 - j1);
      j1 = j;
      i += 8;
      if (i > width) {
      i = 0;
      noStroke();
      fill(218);     
      rect(0,height - 700, width, 350);
      }     
    }
   }
 } 

void plot1() { 
  while (!stopPlot) { 
      if (millis() >= Timer1) {
      Timer1 += Interval_10;
      y += 8;
      if (y > 256) {y = 0;}
      stroke(255);
      strokeWeight(6);
      line(x, height - 50 - y, x++, height - 50 - y1);
      y1 = y;
      x++;
      if (x > width) {
      x = 0;   
      noStroke();
      fill(166,118,60);
      rect(0,height - 350, width, 350);
      }     
    }
  }
}

void mousePressed(){
  if((mouseX >= _stopBtnX) && (mouseX <= _stopBtnX+_stopBtnW) && (mouseY >= _stopBtnY) && (mouseY <= _stopBtnY+_stopBtnH)){
    stopBtn.press();
  }
}
1 Like