G4P - Remember Option Selected in New Window

Good afternoon all;

I’m making a little app and have only gotten as far as setting up the GUI using G4P. I’ve set it up so that there is a floating panel with buttons that open up more windows that let you select certain options. In the ‘Symbols’ button, I have a new window open up with two checkboxes. I want it so that after you close that window, the sketch will remember what you checked. However, when I click ‘Symbols’, check a box, close the window, then re-click ‘Symbols’ to see if the checkboxes are still checked - they’re not. Any idea on what I may need to do? I’ve only included the relevant code and removed code referencing other buttons:

Main Tab

import g4p_controls.*; // Import GUI interface

void setup() {
  size(1080, 720); // size of the screen
  makeControls(); // draw the control panel
  G4P.messagesEnabled(false);
}

void draw() {
  background(255);
}

public void handleButtonEvents(GButton button, GEvent event) {
  if (button == btnSymbols && event == GEvent.CLICKED) {
    createSymbolsWindow();
    btnSymbols.setEnabled(false);
    btnSymbols.setLocalColorScheme(G4P.BLUE_SCHEME);
  }
}

Control Panel

GPanel pnlControls;
GButton btnSymbols;

public void makeControls() {
  // Create the Options Panel
  int pxLoc = 0; 
  int pyLoc = 0;
  float widthVar = 8;
  float heightVar = 3.75;
  float pWidth = width / widthVar; 
  float pHeight = height / heightVar;
  float bDistance = 21; 
  float bWidthVar = 1.05;

  pnlControls = new GPanel(this, pxLoc, pyLoc, pWidth, pHeight, "Options");
  pnlControls.setOpaque(true); 
  pnlControls.setCollapsed(false);
  pnlControls.setLocalColorScheme(G4P.CYAN_SCHEME);
  pnlControls.setAlpha(200, true);

  //Symbols Button
  btnSymbols = new GButton(this, 2, pyLoc + (bDistance * 4), pWidth / bWidthVar, bDistance, "Symbols");
  pnlControls.addControl(btnSymbols);
  btnSymbols.setLocalColorScheme(G4P.CYAN_SCHEME);

Window Controls

GWindow symbolsControl;
GLabel lblSymbolsSelect;
GCheckbox cbxSymbolPoint; 
GCheckbox cbxSymbolTrace;

public void createSymbolsWindow() {
  symbolsControl = GWindow.getWindow(this, "Symbols", 600, 400, 400, 300, JAVA2D);
  PApplet sApp = symbolsControl;
  symbolsControl.setActionOnClose(G4P.CLOSE_WINDOW);
  symbolsControl.addOnCloseHandler(this, "closeSymbolsController");

  lblSymbolsSelect = new GLabel(sApp, 0, sApp.height / 8, sApp.width, sApp.height / 4, "Select which symbols you want to interpret. Choose between symbols to hit points in space, pathways to trace, or both");
  lblSymbolsSelect.setLocalColorScheme(G4P.RED_SCHEME);
  cbxSymbolPoint = new GCheckbox(sApp, 230, 130, 120, 20, "Points in Space");
  cbxSymbolTrace = new GCheckbox(sApp, 230, 150, 120, 20, "Trace Space");

  symbolsControl.addDrawHandler(this, "drawSymbolsController");
}

public void drawSymbolsController(PApplet appc, GWinData data) {
  appc.background(255);
}

public void closeSymbolsController(GWindow window) {
  btnSymbols.setEnabled(true);
  btnSymbols.setLocalColorScheme(G4P.CYAN_SCHEME);
}

This is the problem because you have two new checkboxes whose default state is unselected. One solution would be to remember the state of the old boxes when closing the window then using these when creating the new window.

To do that we need a couple of boolean variables and modify a couple of functions. The code below are the changes I made.

boolean symbolPointSelected, symbolTraceSelected;

public void closeSymbolsController(GWindow window) {
  // Remember the current state of the checkboxes
  symbolPointSelected = cbxSymbolPoint.isSelected();
  symbolTraceSelected = cbxSymbolTrace.isSelected();
  
  btnSymbols.setEnabled(true);
  btnSymbols.setLocalColorScheme(G4P.CYAN_SCHEME);
}

public void createSymbolsWindow() {
  symbolsControl = GWindow.getWindow(this, "Symbols", 600, 400, 400, 300, JAVA2D);
  PApplet sApp = symbolsControl;
  symbolsControl.setActionOnClose(G4P.CLOSE_WINDOW);
  symbolsControl.addOnCloseHandler(this, "closeSymbolsController");

  lblSymbolsSelect = new GLabel(sApp, 0, sApp.height / 8, sApp.width, sApp.height / 4, "Select which symbols you want to interpret. Choose between symbols to hit points in space, pathways to trace, or both");
  lblSymbolsSelect.setLocalColorScheme(G4P.RED_SCHEME);
  cbxSymbolPoint = new GCheckbox(sApp, 230, 130, 120, 20, "Points in Space");
  cbxSymbolTrace = new GCheckbox(sApp, 230, 150, 120, 20, "Trace Space");

  // set the state of the checkboxes to match the previous window
  cbxSymbolPoint.setSelected(symbolPointSelected);
  cbxSymbolTrace.setSelected(symbolTraceSelected);

  symbolsControl.addDrawHandler(this, "drawSymbolsController");
}
1 Like

So I have provided the solution to your problem but there is another problem and that is repeatably creating / destroying secondary windows because

  • Processing does not support multiple windows out of the box so G4P is really pushing the Processing envelope and some it has caused problems with some OSs. See my website guides for more info)
  • Creating and destroying windows is very resource heavy especially if the window has a lot of controls on it.
  • Difficult to maintain state between windows (i.e. your current problem).

So I don’t recommend repeatably creating <> destroying GWindow object and their controls. Instead I recommend that you create all the windows in setup and then make them invisible. Now all you have to do is provide buttons to change its visibility.

I have modified your code to demonstrate this.

import g4p_controls.*; // Import GUI interface

void setup() {
  size(1080, 720); // size of the screen
  makeControls(); // draw the control panel
  G4P.messagesEnabled(false);
}

void draw() {
  background(255);
}

public void handleButtonEvents(GButton button, GEvent event) {
  if (button == btnSymbols && event == GEvent.CLICKED) {
    btnSymbols.setEnabled(false);
    btnSymbols.setLocalColorScheme(G4P.BLUE_SCHEME);
    symbolsControl.setVisible(true);
  }
  if (button == btnSymbolsWindowVisible && event == GEvent.CLICKED) {
    btnSymbols.setEnabled(true);
    btnSymbols.setLocalColorScheme(G4P.BLUE_SCHEME);
    symbolsControl.setVisible(false);
  }
}

GPanel pnlControls;
GButton btnSymbols;

public void makeControls() {
  // Create the Options Panel
  int pxLoc = 0; 
  int pyLoc = 0;
  float widthVar = 8;
  float heightVar = 3.75;
  float pWidth = width / widthVar; 
  float pHeight = height / heightVar;
  float bDistance = 21; 
  float bWidthVar = 1.05;

  pnlControls = new GPanel(this, pxLoc, pyLoc, pWidth, pHeight, "Options");
  pnlControls.setOpaque(true); 
  pnlControls.setCollapsed(false);
  pnlControls.setLocalColorScheme(G4P.CYAN_SCHEME);
  pnlControls.setAlpha(200, true);

  //Symbols Button
  btnSymbols = new GButton(this, 2, pyLoc + (bDistance * 4), pWidth / bWidthVar, bDistance, "Symbols");
  pnlControls.addControl(btnSymbols);
  btnSymbols.setLocalColorScheme(G4P.CYAN_SCHEME);

  // Symbols Window
  symbolsControl = GWindow.getWindow(this, "Symbols", 600, 400, 400, 300, JAVA2D);
  PApplet sApp = symbolsControl;
  symbolsControl.setActionOnClose(G4P.KEEP_OPEN);
  symbolsControl.addOnCloseHandler(this, "closeSymbolsController");
  lblSymbolsSelect = new GLabel(sApp, 0, sApp.height / 8, sApp.width, sApp.height / 4, "Select which symbols you want to interpret. Choose between symbols to hit points in space, pathways to trace, or both");
  lblSymbolsSelect.setLocalColorScheme(G4P.RED_SCHEME);
  cbxSymbolPoint = new GCheckbox(sApp, 230, 130, 120, 20, "Points in Space");
  cbxSymbolTrace = new GCheckbox(sApp, 230, 150, 120, 20, "Trace Space");
  btnSymbolsWindowVisible = new GButton(symbolsControl, sApp.width - 60, sApp.height - 30, 50, 20, "CLOSE");
  symbolsControl.addDrawHandler(this, "drawSymbolsController");
  symbolsControl.setVisible(false);
}

GWindow symbolsControl;
GLabel lblSymbolsSelect;
GCheckbox cbxSymbolPoint; 
GCheckbox cbxSymbolTrace;
GButton btnSymbolsWindowVisible;


public void drawSymbolsController(PApplet appc, GWinData data) {
  appc.background(255);
}
1 Like

@quark Thank you kindly for the detailed responses. Your first response solved the issue but your second response made me think of the construction differently and in a way that’s more optimized (as you noted). Can’t wait to get this app. working as I’ve imagined it :slight_smile:

And, thank you for G4P :slight_smile: