How to start/stop individual windows in multiwindow project?

Hey there! I am having a bit of trouble with this and there seems to be no straightforward way to approach it.

What I am working on is a multiwindow project, designed to be implemented in a yacht/boat display. Each of the windows being is an extended class of PApplet, with it’s own code and things to process. For example, I have created a PCamera class, which loads and displays 6 different camera streams and also a PWindow class that displays speed, gps data and fuel level.

My goal is to switch between these windows with an event (mousePressed() or keyPressed(), not relevant) but at the same time have the previous window dissappear and stop execution, and start execution of the next window. I need to do this because there will be at least 6 windows, each of them heavy on CPU and memory, and all of this has to be implemented on a Raspberry Pi 4…

I have tried using surface.setVisible(false), inside a function, in combination with the stop() method, to try and have each window “stop” and “hide” after the ‘n’ key is pressed. Right now implemented with 2 windows:

void setup() { 
  
  frameRate(20);
  nextWindow=0;
  logo = loadImage("adamas.jpg");
  imageMode(CENTER);
  image(logo,displayWidth/2,displayHeight/2,logo.width/2,logo.height/2);
  
  win1 = new PWindow("CLOCK");
  win1.stop();
  changeVisibleState(win1, true);
  
  cameras = new PCamera("CAMERAS");
  cameras.stop();
  changeVisibleState(cameras, false);

} 

void draw(){
  background(0);
 
  switch(nextWindow){
    case 0:
    cameras.stop();
    win1.start();
    break;
    
    case 1:
    win1.stop();
    cameras.start();
    break;
    
    default: println("No active screens"); break;
    }
}

void keyPressed(){
  if (key =='n'){
    nextWindow = (nextWindow+1)%2;

    switch(nextWindow){
      case 0: 
      changeVisibleState(win1, true);
      changeVisibleState(cameras, false);
      break;
      
      case 1:
      changeVisibleState(win1, false);
      changeVisibleState(cameras, true);
      break;
    }
  }
}

void changeVisibleState(PApplet window, boolean visible){
  window.getSurface().setVisible(visible);
}

The problem is this does not completely kill the execution of the sketch, im only starting and stopping it (as i understand it). Also i have to switch between the diplayed window and the “main” window, which is not hidden, for it to register that a key has been pressed. It’s annoying and not the functionality i want it to have.

So, my question is: is there a way to have the “main” window of the sketch switch to another with a different definition, all while ensuring it is the only one being executed?

Thanks!!

1 Like

so you could ignore all the window things and just take care the work load:

class PWindow extends PApplet {
 public boolean work = false;

//...

 void draw() {
   surface.setTitle("win "+nf(frameRate, 0, 1)+" FPS");
   background(0, 200, 0);

   if ( work ) {
     for ( int i = 0; i < 1000; i++ ) ellipse(random(width), random(height), random(50), random(50));
   }
 }

//...
 public void show() {
   work = true;
   surface.setVisible(true);
 }
 public void hide() {
   work = false;
   surface.setVisible(false);
 }
}  // end PWindow

and in main manipulate as you need.

void mousePressed() {
  println("mousePressed in primary window");
  if ( mouseButton == LEFT )  win.show();
  if ( mouseButton == RIGHT ) win.hide();
} 

void keyPressed() {
  if ( key == 'w' ) {
    win.work = ! win.work;
    println("win work "+win.work );
  }
}


anyhow win draw still runs, so mouse keyboard works… there
just no cpu load from that win-draw-job
the good thing is also that you can separate the draw job in parts

  • need to do in show and hide mode
  • need to do only in show mode == WORK

( looks like a hack… but my cpu monitor show it works fine )

1 Like

Use noLoop() in all the windows you are not using. When you swicth from window A to window B then

A.noLoop(); 
B.loop();
2 Likes

Alternatively reduce the frame rate of unused windows with frameRate() so that it will still respond to the mouse but still reduce the CPU load, a value 10-15 should do it.

1 Like

Good idea, thank you! I still have a problem though, the mouse/keyboard will only respond in the main sketch. What I would like is for any of the 6 windows to handle mouse and keyboard events, depending on which one of them is active. That way, if the mouse is pressed, the current window shuts down and opens the next one, which in turn now handles mouse and keyboard events.

1 Like

you might show your test code for main + 2 wins
as here no problem with windows mouse and keyboard


not sure this is close to the logic you want:

PWindow win1, win2;

void settings() {
  size(300, 200);
}

void setup() { 
  surface.setLocation(20, 20);
  win1 = new PWindow(1);
  win2 = new PWindow(2);
  println("use key [1] [2] for toggle win job [q] [w] for toggle win show\nOR on the respective window:\nmouseclick LEFT work / mouseclick RIGHT stop and hide");
}

void draw() {
  surface.setTitle("main "+nf(frameRate, 0, 1)+" FPS");
  background(200, 200, 0);
}

void mousePressed() {
  println("mousePressed in primary window");
} 

void keyPressed() {
  if ( key == '1' ) {
    win1.work = ! win1.work;
    println("win1 work "+win1.work );
    if ( win1.work ) win1.show();
  }
  if ( key == 'q' ) {
    if ( win1.work ) { win1.work = false; win1.hide(); }
    else {  win1.work = true; win1.show(); }
    println("key "+key+" win2 work "+win2.work );
  }
  if ( key == '2' ) {
    win2.work = ! win2.work;
    println("win2 work "+win2.work );
    if ( win2.work ) win2.show();
  }
  if ( key == 'w' ) {
    if ( win2.work ) { win2.work = false; win2.hide(); }
    else {  win2.work = true; win2.show(); }
    println("key "+key+" win2 work "+win2.work );
  }
}

// https://discourse.processing.org/t/closing-a-second-window/381/10
@Override void exit() {
  win1.dispose();
  win1 = null;
  win2.dispose();
  win2 = null;
  super.exit();
}


//_______________________________
class PWindow extends PApplet {
  public boolean work = false;
  public int num;
  PWindow(int num) {
    super();
    this.num = num;
    PApplet.runSketch(new String[] {this.getClass().getSimpleName()}, this);
  }

  void settings() {
    size(400, 400, P3D);
  }

  void setup() {
    setDefaultClosePolicy(this, false);
    surface.setLocation(20+400*num, 320);
  }

  void draw() {
    surface.setTitle("win"+num+": "+nf(frameRate, 0, 1)+" FPS");//+" focus "+this.focused);//one is false one is true???
    background(0, 200, 0);

    if ( work ) {
      for ( int i = 0; i < 1000; i++ ) ellipse(random(width), random(height), random(50), random(50));
    }
  }

  void mousePressed() {
    println("mousePressed in secondary window");
    if ( mouseButton == LEFT ) { 
      if ( ! work ) work=true;
    }
    if ( mouseButton == RIGHT ) { 
      work=false;
      println(" stop work and hide ");
      this.hide();
    }
  }

  void keyPressed() {
    println("keyPressed in secondary window");
  }

  void exit() {
    dispose();
  }

  final void setDefaultClosePolicy(PApplet pa, boolean keepOpen) {
    final Object surf = pa.getSurface().getNative();
    final PGraphics canvas = pa.getGraphics();

    if (canvas.isGL()) {
      final com.jogamp.newt.Window w = (com.jogamp.newt.Window) surf;

      for (com.jogamp.newt.event.WindowListener wl : w.getWindowListeners())
        if (wl.toString().startsWith("processing.opengl.PSurfaceJOGL"))
          w.removeWindowListener(wl); 

      w.setDefaultCloseOperation(keepOpen?
        com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode
        .DO_NOTHING_ON_CLOSE :
        com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode
        .DISPOSE_ON_CLOSE);
    } else if (canvas instanceof processing.awt.PGraphicsJava2D) {
      final javax.swing.JFrame f = (javax.swing.JFrame)
        ((processing.awt.PSurfaceAWT.SmoothCanvas) surf).getFrame(); 

      for (java.awt.event.WindowListener wl : f.getWindowListeners())
        if (wl.toString().startsWith("processing.awt.PSurfaceAWT"))
          f.removeWindowListener(wl);

      f.setDefaultCloseOperation(keepOpen?
        f.DO_NOTHING_ON_CLOSE : f.DISPOSE_ON_CLOSE);
    }
  }

  public void show() {
    work = true;
    surface.setVisible(true);
  }
  public void hide() {
    work = false;
    surface.setVisible(false);
  }
}  // end PWindow

in main not configured mouse to operate child windows, but with 4 buttons possible

1 Like

I have tried this method and solved some problems, but I’m still struggling with some issues. The keyboard events are handled by the current window, which is what I expect, and the windows seem to be stopping and hiding correctly, but now I have the problem of switching between windows.

In my code, I switch between 2 windows by pressing ‘1’ or ‘2’ in the main sketch, but since I want all windows except the current one to be hidden and stopped, I need a way to switch between them if im currently in window 2, for example. Bare in mind that the final implementation will have at least 6 windows, so I’m thinking I need some kind of “counter” that knows which window I’m in right now and which one’s next.

Here’s my code:

Main:

public void settings() {
  fullScreen();
}

void setup() { 

  frameRate(20);
  nextWindow=0;
  logo = loadImage("adamas.jpg");
  imageMode(CENTER);
  image(logo,displayWidth/2,displayHeight/2,logo.width/2,logo.height/2);
  // this.hide();
  
  win1 = new PWindow("RELOJ");
  //win1.show();
  
  cameras = new PCamera("CAMARAS");
  //cameras.hide();
} 

void draw(){
  background(0);
 if (millis()<2000) image(logo,displayWidth/2,displayHeight/2,logo.width/2,logo.height/2);
}

void keyPressed(){
  if (key == 'h'){
    switchHDMI();
  }
  if (key == 'u'){
    switchUSB();
  }
  if (key =='1'){
    //nextWindow = (nextWindow+1)%2;
    cameras.hide();
    win1.show();
  }
  if (key == '2'){
    win1.hide();
    cameras.show();
  }
}
void switchHDMI(){
// ... //
}

void switchUSB(){
// ... //
}
  
public void hide(){
    surface.setVisible(false);
  }

@Override void exit(){
  win1.dispose();
  win1 = null;
  cameras.dispose();
  cameras = null;
  super.exit();
}

PCamera class:

public class PCamera extends PApplet {

  PCamera(String name) {
    super();
    PApplet.runSketch(new String[] {this.getClass().getSimpleName()}, this);
   surface.setTitle(name);
   surface.setLocation(0,0);
  }

public boolean work = false;
IPCapture cam1, cam2, cam3, cam4, cam5, cam6;
int cont;


 void settings() {
   //size(640,480);
  
   fullScreen();
   frameRate=20;

 }

void setup() {
setDefaultClosePolicy(this, false);
iniciarCamaras();
}


void draw() {  
  background(0);
  if(work){
      switch(this.cont){
      case 0:
        if (cam1.isAvailable()) {
            cam1.read();
        }
        if (cam2.isAvailable()) {
            cam2.read();
        }
        if (cam3.isAvailable()) {
            cam3.read();
        }
        if (cam4.isAvailable()) {
            cam4.read();
        }
        if (cam5.isAvailable()) {
            cam5.read();  
        }
        if (cam6.isAvailable()) {
            cam6.read();
        }
        image(cam1,0,0, 640, 480);
        image(cam2,displayWidth/3,0, 640, 480);
        image(cam3,2*displayWidth/3,0, 640, 480);
        image(cam4,0,480, 640, 480);
        image(cam5,displayWidth/3,480, 640, 480);
        image(cam6,2*displayWidth/3,480, 640, 480);
      break;
      
      case 1:    
      if (cam1.isAvailable()) {
            cam1.read();
            image(cam1,0,0, displayWidth, displayHeight);
        } break;
      case 2:
      if (cam2.isAvailable()) {
            cam2.read();
            image(cam2,0,0, displayWidth, displayHeight);
        } break;
      case 3: 
      if (cam3.isAvailable()) {
            cam3.read();
            image(cam3,0,0, displayWidth, displayHeight);
        } break;
      case 4: 
      if (cam4.isAvailable()) {
            cam4.read();
            image(cam4,0,0, displayWidth, displayHeight);
        } break;
      case 5: 
      if (cam5.isAvailable()) {
            cam5.read();
            image(cam5,0,0, displayWidth, displayHeight);
        } break;
      case 6:
      if (cam6.isAvailable()) {
            cam6.read();
            image(cam6,0,0, displayWidth, displayHeight);
        } break;
    }
  }
  }

void keyPressed() {
  if (key == 's') {
  // Changes camera
    }
  }
  if (key == 'n'){
    work = false;
    println(" stop work and hide ");
    this.hide();
  }
}
  
void mouseClicked() {
 // ... //
}

void iniciarCamaras(){
  // ... //
}

void pararCamaras(){
// ... //
 }
 
void exit(){
  dispose();
}
 
public void show(){
   work = true;
   surface.setVisible(true);
 }
 
public void hide(){
   //pararCamaras();
   work = false;
   surface.setVisible(false);
 }
 
final void setDefaultClosePolicy(PApplet pa, boolean keepOpen){
  
  final Object surf = pa.getSurface().getNative();
    final PGraphics canvas = pa.getGraphics();

    if (canvas.isGL()) {
      final com.jogamp.newt.Window w = (com.jogamp.newt.Window) surf;

      for (com.jogamp.newt.event.WindowListener wl : w.getWindowListeners())
        if (wl.toString().startsWith("processing.opengl.PSurfaceJOGL"))
          w.removeWindowListener(wl); 

      w.setDefaultCloseOperation(keepOpen?
        com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode
        .DO_NOTHING_ON_CLOSE :
        com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode
        .DISPOSE_ON_CLOSE);
    } else if (canvas instanceof processing.awt.PGraphicsJava2D) {
      final javax.swing.JFrame f = (javax.swing.JFrame)
        ((processing.awt.PSurfaceAWT.SmoothCanvas) surf).getFrame(); 

      for (java.awt.event.WindowListener wl : f.getWindowListeners())
        if (wl.toString().startsWith("processing.awt.PSurfaceAWT"))
          f.removeWindowListener(wl);

      f.setDefaultCloseOperation(keepOpen?
        f.DO_NOTHING_ON_CLOSE : f.DISPOSE_ON_CLOSE);
    }
}

PWindow class:

class PWindow extends PApplet {

  PWindow(String name) {
    super();
    PApplet.runSketch(new String[] {this.getClass().getSimpleName()}, this);
   surface.setTitle(name);
   surface.setLocation(0,0);
  }
  
  void settings() { 
    //size(displayWidth,displayHeight);
   fullScreen();
 }

  void setup() {
    frameRate(20);
    setDefaultClosePolicy(this, false);
    inicializa_pantalla();
  delay(1000);
  }

void draw() {
    if(work){
  animacion_variables(); 
  dibuja_pantalla(); 
  dibuja_menu(menu);
    }
 }
void inicializa_pantalla() {
// ... //
}
void visualiza_textos_pantalla(){
 // ... //
  }
void  visualiza_imagenes_pantalla(){
// ... //
}
void repintaFondo(int x, int y, int w, int h){
// ... //
}
void dibuja_pantalla() {
  visualiza_textos_pantalla();
  visualiza_imagenes_pantalla();
}
void dibuja_menu(boolean menu){
 // ... //
  }  
}
void mousePressed(){
 tiempo = millis();
 println(tiempo);
}

long tiempoActivado;
void mouseReleased(){
  if(millis()-tiempo>1500){
    tiempoActivado = millis();
    menu = true;
  }  
}

void keyPressed(){
    if (key == 'n'){
    work = false;
    println(" stop work and hide ");
    this.hide();
  }
}
boolean hanPasadoXSegundos(){
  if(millis()-tiempoActivado>3000){
    println("devuelvo falso");
    return false;
  }else
    return true;
}
void handleToggleButtonEvents(GImageToggleButton button, GEvent event){
}

public void show(){
   work = true;
   surface.setVisible(true);
}

public void hide(){
  work = false;
  surface.setVisible(false);
}

void exit(){
  dispose();
}

final void setDefaultClosePolicy(PApplet pa, boolean keepOpen){
  
  final Object surf = pa.getSurface().getNative();
    final PGraphics canvas = pa.getGraphics();

    if (canvas.isGL()) {
      final com.jogamp.newt.Window w = (com.jogamp.newt.Window) surf;

      for (com.jogamp.newt.event.WindowListener wl : w.getWindowListeners())
        if (wl.toString().startsWith("processing.opengl.PSurfaceJOGL"))
          w.removeWindowListener(wl); 

      w.setDefaultCloseOperation(keepOpen?
        com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode
        .DO_NOTHING_ON_CLOSE :
        com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode
        .DISPOSE_ON_CLOSE);
    } else if (canvas instanceof processing.awt.PGraphicsJava2D) {
      final javax.swing.JFrame f = (javax.swing.JFrame)
        ((processing.awt.PSurfaceAWT.SmoothCanvas) surf).getFrame(); 

      for (java.awt.event.WindowListener wl : f.getWindowListeners())
        if (wl.toString().startsWith("processing.awt.PSurfaceAWT"))
          f.removeWindowListener(wl);

      f.setDefaultCloseOperation(keepOpen?
        f.DO_NOTHING_ON_CLOSE : f.DISPOSE_ON_CLOSE);
    }
}
}
1 Like

sorry, worked on a main window optional menu button bar
to operate all windows,
but for unknown reasons it not runs stable??
so no help from this side.


also i tried to use the
https://processing.org/reference/focused.html
also did not work


i could also NOT get your code running,
( i am having a bad day? )

but now i understand, you created your problem mostly by the

fullScreen();

for all the child windows.
hm, a child window can not operate other windows??
so it must before it is

    this.hide();

? same as ?

   surface.setVisible(false);

( keyboard action different mouse action ?)

report back to main ( set a global )
its (int num) why you use (String name) makes it more difficult.

so main would be able to see ( num ) went to hide so it can do like
win[num+1].show();

1 Like