G4P - Checkbox grid

Is possible to easily create a Check box grid? Like 8x8 or bigger.

Thanks!

Hey, can you please show your attempt?

Can you make one check box?

One way is a nested for loop and store everything in an array or Arraylist

1 Like

You might try the GUI Builder tool (can install from Contribution Manager). This tool helps you design and create GUIs with G4P.

The link above takes you to my website where there are a number of videos showing how to use GUI Builder.

If you don’t want to use GUI Builder then this example shows how you can create a grid of checkboxes from a 2D String array. Since Java treats 2D arrays as a 1D array of arrays we can create irregular arrangements as shown in this sketch.

import g4p_controls.*;

String[][] shopping_list = {
  {"Apples", "Pears", "Oranges", "Bananas"}, // Row 1 has 4 boxes
  {"Lamb", "Beef", "Pork", "Buscuits"}, // Row 2 has 4 boxes
  {"Salt", "Pepper"}, // Row 3 has 2 boxes
  {"Jam", "Marmalade", "Tomatos"}, // Row 4 has 3 boxes
  {"Wheatabix", "Butter", "Marmite", "Pizza"}   // Row 5 has 4 boxes
};

void setup() {
  size(600, 300);
  G4P. messagesEnabled(false);
  makeShoppingList();
}

void makeShoppingList() {
  GCheckbox cbx;
  for (int row = 0; row < shopping_list.length; row ++) {
    for (int col = 0; col < shopping_list[row].length; col ++) {
      cbx = new GCheckbox(this, col * 100 + 20, row * 25 + 30, 90, 20, shopping_list[row][col]);
      cbx .addEventHandler(this, "shoppingListChange");
    }
  }
}

void shoppingListChange(GCheckbox source, GEvent event) {
  String action = event == GEvent.SELECTED ? " ADDED " : " REMOVED ";
  println(source.getText() + action + "\t" + millis());
}

void draw() {
  background(200, 200, 255);
}
3 Likes

Hey Quark! I Love your library!

I already use the tool, but my problem is that to create an grid with the tool I need to create each one individually.

Imagine that I need an 8x8 grid, and have to store all states. If it used the tool I have to create a Checkbox and name it to a variable, but that is very slow.

I will try your solution, if it works or not I will return here to discuss it.

Thanks a lot!

here the check boxes get shown in an 2D Array / grid - see tutorial “two-dimensional arrays”

probably there are simpler ways to do this…

somehow rows and cols are swapped in the array…???

Chrisir


// somehow rows and cols are swapped in the array...???


import g4p_controls.*;

String[][] shopping_list = {
  {"Apples", "Pears", "Oranges", "Bananas"}, // Row 1 has 4 boxes
  {"Lamb", "Beef", "Pork", "Buscuits"}, // Row 2 has 4 boxes
  {"Salt", "Pepper", "c1", "c2"}, // Row 3 
  {"Jam", "Marmalade", "Tomatos", "c3"}, // Row 4 
  {"Wheatabix", "Butter", "Marmite", "Pizza"}   // Row 5 has 4 boxes
};

String[][] result = {
  {"_", "_", "_", "_"}, // Row 1 has 4 boxes
  {"_", "_", "_", "_"}, // Row 2 has 4 boxes
  {"_", "_", "_", "_"}, // Row 3 
  {"_", "_", "_", "_"}, // Row 4 
  {"_", "_", "_", "_"}  // Row 5 has 4 boxes
};

HashMap<String, Integer>  hmX= new HashMap<String, Integer>();
HashMap<String, Integer>  hmY= new HashMap<String, Integer>();

void setup() {
  size(1600, 300);
  G4P. messagesEnabled(false);
  makeShoppingList();
  for (int row = 0; row < result.length; row ++) {
    for (int col = 0; col < result[row].length; col ++) {
      result[row][col]="_";
    }
  }
}

void makeShoppingList() {
  GCheckbox cbx;
  for (int row = 0; row < shopping_list.length; row ++) {
    for (int col = 0; col < shopping_list[row].length; col ++) {
      cbx = new GCheckbox(this, col * 100 + 20, row * 25 + 30, 90, 20, shopping_list[row][col]);
      cbx .addEventHandler(this, "shoppingListChange");
      //println(shopping_list[row][col]); 
      hmX.put(shopping_list[row][col], row); 
      hmY.put(shopping_list[row][col], col);
    }
  }
}

void shoppingListChange(GCheckbox source, GEvent event) {
  println(source.getText() );

  String action = event == GEvent.SELECTED ? " ADDED " : " REMOVED ";

  boolean state =  event == GEvent.SELECTED ? true : false;

  // We can also access values by their key
  int row = hmX.get(source.getText() );
  int col = hmY.get(source.getText() );

  if (state)
    result[row][col] = "1";
  else result[row][col] = "_";

  println(source.getText() + action + "\t" + millis());
}

void draw() {
  background(200, 200, 255);

  fill(0); 
  for (int row = 0; row < result.length; row ++) {
    for (int col = 0; col < result[row].length; col ++) {
      text (  result[row][col], 
        col * 100 + 620, row * 25 + 30);
    }
  }
}
//

1 Like

In my example each checkbox had its own text label e.g. “Apples” but you say

So do the checkboxes have their own text description or is it simply the position (i.e. row column position) inside the grid that is important? If it is the later then there is an easy way to do it.

Perhaps you could give a little more info about what the grid will be used for :smile:

2 Likes

I need a grid to control an 8x8 “true/false” array. So only the position matters, not the name.

Working on an example - hang on :smile:

1 Like

OK this is a fairly sophisticated example because it has a class to encapsulate a 2D grid of checkboxes. The advantage is that the class does all the hard work in creating the checkboxes and allows for more than one grid (the example has 2 grids).

Try out the example and if you have questions then I will try and answer them.

import g4p_controls.*;

// Demonstration of a 2D grid of checkboxes. The size of the grid is user defineable.
// 
CheckboxGrid cbg0, cbg1;


void setup() {
  size(600, 400);
  G4P.messagesEnabled(false);
  cbg0 = new CheckboxGrid(this, 20, 50, 10, 8, 8);
  cbg1 = new CheckboxGrid(this, 400, 250, 0, 3, 5);
}

void draw() {
  background(200, 200, 255);
}

/*
This class encapsulates a 2D array of checkboxes
 */
public class CheckboxGrid {

  final GCheckbox [][] grid;
  final int nbrRows, nbrCols;

  /*
   Use this constructor to create the grid
   */
  CheckboxGrid(PApplet papp, 
    int left, int top, // top left corner of box encompassing all checkboxes
    int gutter, // The spacing between each row and column
    int nbrRows, int nbrCols // number of rows and columns in the grid
    ) {
    this.nbrRows = nbrRows;
    this.nbrCols = nbrCols;
    grid = new GCheckbox[nbrRows][nbrCols];
    int colSpace = 20 + gutter;
    int rowSpace = 16 + gutter;
    for (int row = 0; row < nbrRows; row ++) {
      for (int col = 0; col < nbrCols; col ++) {
        GCheckbox cbx = new GCheckbox(papp, col * colSpace + left, row * rowSpace + top, 20, 10);
        cbx.tagNo = row * 10000 + col;
        cbx.tag = "Box [row " + row + ",  col " + col +"]";
        cbx.addEventHandler(this, "handleEvents");
        grid[row][col] = cbx;
      }
    }
  }

  /*
   Probably don't need this since you will be checking the state using getState(...)
   in the main code
   */
  public void handleEvents(GCheckbox source, GEvent event) {
    String action = event == GEvent.SELECTED ? " was SELECETED " : " was DESELECETED ";
    println(source.tag + action + "\t" + millis());
  }

  /*
   Get the state (true / false) of a checkbox based on its position in the grid.
   If the user specifies a position outside the grid it returns false.
   */
  public boolean getState(int row, int col) {
    if (row >=0 && row <= nbrRows && col >= 0 && col <= nbrCols) {
      return grid[col][row].isSelected();
    }
    return false; // row, col is not inside grid
  }

  /*
   Allows the user to set the state of a particular checkbox instead of clicking on it
   If the user specifies a position outside the grid it does nothing.
   */

  public void setState(int row, int col, boolean state) {
    if (row >=0 && row <= nbrRows && col >= 0 && col <= nbrCols) {
      grid[row][col].setSelected(state);
    }
  }
}
2 Likes

Wow! Thanks for the example!
So, this is almost what I need, I just need to put this in a separate window.
In special an window that pops up if I click a button, but this I can handle by myself.

How can I draw the grid in another window?

This is quite simple and does not require you to modify the CheckboxGrid class. Simply create the GWindow, add a draw handler with a background statement and pass the reference to the new window in the CheckboxGrid constructor.

This is a modified version of my previous example. It will create 2 extra windows and 3 CheckboxGrids, one for each window.

import g4p_controls.*;

// Demonstration of a 2D grid of checkboxes. The size of the grid is user defineable.
// 
CheckboxGrid cbg0, cbg1, cbg2;
GWindow gw0, gw1, gw2;

void setup() {
  size(600, 400);
  G4P.messagesEnabled(false);
  // First create the windows
  gw1 = GWindow.getWindow(this, "Window gw1", 30, 50, 180, 200, JAVA2D);
  gw2 = GWindow.getWindow(this, "Window gw2", 300, 60, 160, 220, JAVA2D);
  // Now the grids
  cbg0 = new CheckboxGrid(this, 20, 50, 10, 8, 8);
  cbg1 = new CheckboxGrid(gw1, 20, 20, 8, 3, 5);
  cbg2 = new CheckboxGrid(gw2, 10, 30, 8, 7, 4);
  // Finally the draw handlers for the extra windows.
  gw1.addDrawHandler(this, "win_draw_1");
  gw2.addDrawHandler(this, "win_draw_2");
}

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

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


void draw() {
  background(200, 200, 255);
}

/*
This class encapsulates a 2D array of checkboxes
 */
public class CheckboxGrid {

  final GCheckbox [][] grid;
  final int nbrRows, nbrCols;

  /*
   Use this constructor to create the grid
   */
  CheckboxGrid(PApplet papp, 
    int left, int top, // top left corner of box encompassing all checkboxes
    int gutter, // The spacing between each row and column
    int nbrRows, int nbrCols // number of rows and columns in the grid
    ) {
    this.nbrRows = nbrRows;
    this.nbrCols = nbrCols;
    grid = new GCheckbox[nbrRows][nbrCols];
    int colSpace = 20 + gutter;
    int rowSpace = 16 + gutter;
    for (int row = 0; row < nbrRows; row ++) {
      for (int col = 0; col < nbrCols; col ++) {
        GCheckbox cbx = new GCheckbox(papp, col * colSpace + left, row * rowSpace + top, 22, 10, " ");
        cbx.tagNo = row * 10000 + col;
        cbx.tag = "Box [row " + row + ",  col " + col +"]";
        cbx.addEventHandler(this, "handleEvents");
        grid[row][col] = cbx;
      }
    }
  }

  /*
   Probably don't need this since you will be checking the state using getState(...)
   in the main code
   */
  public void handleEvents(GCheckbox source, GEvent event) {
    String action = event == GEvent.SELECTED ? " was SELECETED " : " was DESELECETED ";
    println(source.tag + action + "\t" + millis());
  }

  /*
   Get the state (true / false) of a checkbox based on its position in the grid.
   If the user specifies a position outside the grid it returns false.
   */
  public boolean getState(int row, int col) {
    if (row >=0 && row <= nbrRows && col >= 0 && col <= nbrCols) {
      return grid[col][row].isSelected();
    }
    return false; // row, col is not inside grid
  }

  /*
   Allows the user to set the state of a particular checkbox instead of clicking on it
   If the user specifies a position outside the grid it does nothing.
   */

  public void setState(int row, int col, boolean state) {
    if (row >=0 && row <= nbrRows && col >= 0 && col <= nbrCols) {
      grid[row][col].setSelected(state);
    }
  }
}
2 Likes

Be careful here, I recommend that you create the window in setup and then hide/show the window as and when required using setVisible(true/false). Do NOT destroy a window with close() if you plan to recreate it later - you can read more about this on my website.

2 Likes

Thank you so much for you help! I really appreciate your work.

Your library is the best and I allways use it.

Thank you again!

1 Like