Arranging an array of objects in a grid

I’m trying to further my understanding of how to implement an object array with this simple sketch.

  • I created a while loop within a while loop to create the grid.
  • I added the object array
  • But the screen appears empty without an error message when i run the sketch.

It’s probably a very simple oversight, but I can’t figure out what I’ve done wrong.

Code below /////////////////////////////////////////////

Button [] myButtons = new Button [25];

void setup() {
  size (600, 600);

  for (int i = 0; i < myButtons.length; i++) {
    myButtons [i] = new Button (int(random(255)), random(25, 50));
  }
}

void draw() {
  background (255);
  float x = 0;
  float y = 0;

  for (int i = 0; i < myButtons.length; i++) {

    //float x = 0;
    while (x < width) {
      //float y = 0;
      while (y < height) {

        myButtons[i].display();
      }
    }
    y = y + 25;
  }
  x = x + 25;
}
void mousePressed() {
  
  for (int i = 0; i < myButtons.length; i++) {
    myButtons[i].click();
  }
}

CLASS ///////////////////////////////////////////////////////////

class Button {
  float x;
  float y;
  color col;
  float sz;
  boolean on;

  Button(color tempCol, float tempSz) {
    col = tempCol;
    sz = tempSz;

    //checking for edges

    if (x+sz>=width)
      x=width-sz-1; 

    if (y+sz>=height)
      y=height-sz-1; 

    // button starts in the off position 
    on = false;
  }

  void display() {

    // fill + stroke appearance when button is on / off

    if (on) {
      fill (255);
      stroke(0);
    } else {
      fill (0);
      stroke (255);
    }
    rect (x, y, sz, sz);
  }
  
  void click() {
    if (mouseX > x && mouseX < x + sz && mouseY > y && mouseY < y + sz) {
      on = !on;
    }
  }
}

Any guidance most welcome and appreciated!!
:slightly_smiling_face:

1 Like

i think it would make more sense if the buttons KNOW where they are.

  Button(float x, float y, color tempCol, float tempSz) {

This doesn’t seem to work. See below. Is this what you meant?

In Button class I changed to:

Button(float x, float y, color tempCol, float tempSz) {

In main program I changed to:

void setup() {
  size (600, 600);

  for (int i = 0; i < myButtons.length; i++) {
    myButtons [i] = new Button (0, 0, int(random(255)), random(25, 50));
  }

my idea of a GRID

//_______________________________________GRID array of class
int x=10, y=x, w=100, h=w, off=5, grid=5, many=grid*grid;    // adjust grid 
Button [] myButtons = new Button [many];

void setup() {
  size (600, 600);
  for (int i = 0; i < many; i++)
    myButtons [i] = new Button ( x+(i%grid)*( w+off), y+(floor(i/grid))*(h+off), w, h, int(random(255)), random(25, 50));
}

void draw() {
  background (255);
  for (int i = 0; i < many; i++)  myButtons[i].display();
}

void mousePressed() {
  for (int i = 0; i < many; i++)   myButtons[i].click();
}

class Button {
  float x, y, w, h;
  color col;
  float sz;
  boolean on = false;   // button starts in the off position

  Button(float tempx, float tempy, float tempw, float temph, color tempCol, float tempSz) {
    x=tempx;
    y=tempy;
    w=tempw;
    h=temph;
    col = tempCol;
    sz = tempSz;
    if (x+sz>=width)  x=width-sz-1;   //checking for edges
    if (y+sz>=height) y=height-sz-1; 
  }

  void display() {
    if (on) {    // fill + stroke appearance when button is on / off
      fill (255);
      stroke(0);
    } else {
      fill (0);
      stroke (255);
    }
    rect (x, y, w,h); //sz, sz);
  }

  void click() {
//    if (mouseX > x && mouseX < x + sz && mouseY > y && mouseY < y + sz)  on = !on;
    if (mouseX > x && mouseX < x + w && mouseY > y && mouseY < y + h)  on = !on;
  }
}

2 Likes

@kii
I just want to make sure I understand the concept.
It looks like I need to create a grid via an array? To connect with the array of button objects?
And that I cannot have a while loop within a while loop with an array of objects?

hm, i just say, if you know you want make a ?fixed? grid,

  • you design it ( in my first line )
int x=10, y=25, w=100, h=20, off=15, grid=5, many=12; //grid*grid;    // adjust grid 

and hand the design to the buttons memory
( and that way the void click() and void draw() can work with it )
but many other ways possible.
i just wanted to help you to get started.


personally i avoid while loops,
until now only needed once.

I will study this some more.

Regarding while loops, I was trying to follow an Abe Pazos tutorial on youtube to make a grid with a while loop within a while loop. But I also, recall D Shiffman stating he, like you, also rarely uses while loops…

Thank you @kii !!

1 Like

with my above grid math there is only the loop over the number of buttons / array length needed.
also a double for loop over x grid and y grid is avoided that way,
but yes, it would be better readable.

still above is more easy for special cases: example
grid = 5; means 5 button ( or rect ) to the right,
many = 12; means make 2 rows with 5 buttons and a 3d row with 2 buttons,

using double FOR or WHILE loops ( for a not 5 * 5 GRID ) would get tricky.

Hey Debby,

instead of your nested while loops you can use a nested for loop. (You could use while too).

I use this in setup() to calculate the x and y position of each cell.

Nested = inner for-loop INSIDE the outer for-loop (they are for x and y position in the grid.).

The array myButtons is filled with objects derived from the class Button.

It looks like I need to create a grid via an array?

The objects in the array are positioned as a grid. The array is the grid.

I hope that makes it clear.

Regards, Chrisir

// GRID array of a class

int grid=5, // how many cells per row and column
  many=grid*grid;    // how many in total 

Button [] myButtons = new Button [many];

void setup() {
  size (600, 600);

  int x=40, y=x, // dist from screen border 
    w=100, h=w, // width and height of one cell 
    off=5;  // dist between cells 

  int k=0; 
  for (int i = 0; i < grid; i++) {
    for (int i2 = 0; i2 < grid; i2++) {
      myButtons [k] = new Button ( x+ i *( w+off), y+ i2 *(h+off), 
        w, h, 
        int(random(255)), 
        25 ); // 25 = size
      k++;
    }
  }
}

void draw() {
  background (255);
  for (int i = 0; i < many; i++) 
    myButtons[i].display();
}

// -----------------------------------------------------------------

void mousePressed() {
  for (int i = 0; i < many; i++) 
    myButtons[i].click();
}

// ====================================================================================

class Button {
  float x, y, w, h;
  color col;
  float sz;
  boolean on = false;   // button starts in the off position

  Button(float tempx, float tempy, 
    float tempw, float temph, 
    color tempCol, 
    float tempSz) {
    x=tempx;
    y=tempy;
    w=tempw;
    h=temph;
    col = tempCol;
    sz = tempSz;

    //checking for edges
    if (x+sz>=width)  
      x=width-sz-1;  
    if (y+sz>=height)
      y=height-sz-1;
  }

  void display() {
    if (on) {    // fill + stroke appearance when button is on / off
      fill (255);
      stroke(0);
    } else {
      fill (col);
      stroke (255);
    }
    rect (x, y, w, h); //sz, sz);
  }

  void click() {
    if (mouseX > x && 
      mouseX < x + w && 
      mouseY > y && 
      mouseY < y + h) 
      on = !on; // toggle
  }
  //
}//class
//
3 Likes

Thank you @Chrisir!! :grinning: :grinning: :grinning:
That works and I understand what’s going on throughout the code!
I made a couple of small adjustments so that the buttons are centered within each cell and button size varies.
Thank you again!!
If you’re curious, this is what the final version looks like:
//////////////////////////////////////////////////////////////////////////////


int grid = 5, // how many cells per row and column
  many = grid*grid;    // how many in total 

Button [] myButtons = new Button [many];

void setup() {
  size (600, 600);

  int x = 40, y = x, // dist from screen border 
    w = 100, h = w, // width and height of one cell 
    off = 5;  // dist between cells 

  

  int k = 0; // k = the 3rd counter
  for (int i = 0; i < grid; i++) { // i = the 1st counter
    for (int i2 = 0; i2 < grid; i2++) { // i2 = the 2nd counter
      myButtons [k] = new Button ( x + i * (w + off), y + i2 * (h + off), 
        w, h, 
        int(random(255)), 
        random(50, 110)); // 25 = size
      k++;
    }
  }
}

void draw() {
  background (255);
  
  translate( 50, 50); // position each button at center of each cell
  
  for (int i = 0; i < many; i++) 
    myButtons[i].display();
}

// -----------------------------------------------------------------

void mousePressed() {
  for (int i = 0; i < many; i++) 
    myButtons[i].click();
}

// ====================================================================================

class Button {
  float x, y, w, h;
  color col;
  float sz;
  boolean on = false;   // button starts in the off position

  Button(float tempx, float tempy, 
    float tempw, float temph, 
    color tempCol, 
    float tempSz) {
    x=tempx;
    y=tempy;
    w=tempw;
    h=temph;
    col = tempCol;
    sz = tempSz;

    //checking for edges
    if (x+sz>=width)  
      x=width-sz-1;  
    if (y+sz>=height)
      y=height-sz-1;
  }

  void display() {
    if (on) {    // fill + stroke appearance when button is on / off
      fill (255);
      stroke(0);
    } else {
      fill (col);
      stroke (255);
    }
    rectMode(CENTER); // draw rect from ctr
    rect (x, y, sz, sz); //sz, sz);
  }

  void click() {
    if (mouseX > x && 
      mouseX < x + w && 
      mouseY > y && 
      mouseY < y + h) 
      on = !on; // toggle
  }
  //
}//class
1 Like

Thank you @kii!!
I think I mostly understand the code and why this works as a grid structure.
However, one question:

  • Why do all of the buttons appear black? In constructor color = int(random(255)) Shouldn’t each appear as a random gray?
int x=10, y=x, w=100, h=w, off=5, grid=5, many=grid*grid;    // adjust grid 

Button [] myButtons = new Button [many];

void setup() {
  size (600, 600);
  for (int i = 0; i < many; i++)
    myButtons [i] = new Button (x + (i % grid)*(w + off), y + (floor(i/grid))*(h + off), w, h, int(random(255)), random(50, 100));
}

void draw() {
  background (255);
  translate (75, 75);
  for (int i = 0; i < many; i++)  myButtons[i].display();
}

void mousePressed() {
  for (int i = 0; i < many; i++)   myButtons[i].click();
}

///////////////////////////////

class Button {
  float x, y, w, h;
  color col;
  float sz;
  boolean on = false;   // button starts in the off position

  Button(float tempx, float tempy, float tempw, float temph, color tempCol, float tempSz) {
    x=tempx;
    y=tempy;
    w=tempw;
    h=temph;
    col = tempCol;
    sz = tempSz;
    if (x+sz>=width)  x=width-sz-1;   //checking for edges
    if (y+sz>=height) y=height-sz-1; 
  }

  void display() {
    if (on) {    // fill + stroke appearance when button is on / off
      fill (255);
      stroke(0);
    } else {
      fill (0);
      stroke (255);
    }
    rectMode (CENTER);
    
    rect (x, y, sz, sz); //sz, sz);
  }

  void click() {
//    if (mouseX > x && mouseX < x + sz && mouseY > y && mouseY < y + sz)  on = !on;
    if (mouseX > x && mouseX < x + w && mouseY > y && mouseY < y + h)  on = !on;
  }
}
1 Like

you hand the random color down to the class memory ‘col’

but in void display only use

stroke(0);
fill(0);

try

fill(col);
1 Like

Thank you @kll, that solved it. :grinning: :grinning:

1 Like

Well done!

There is a small misunderstanding:

This line doesn’t position each button at center of each cell.

it just moves (translates) everything (the entire grid) to the right and to the left by 50.

The center positioning is done here in fact:

    rectMode(CENTER); // draw rect from ctr
    rect (x, y, sz, sz); //sz, sz);

Explanation

because you inserted this line rectMode(CENTER) the x,y position of each cell is now not the upper right corner anymore but the center of the cell (rect command is seeing x,y now as the center of each rectangle). Therefore everything was too far up and too far left.

Therefore, you did the translate() to compensate that.

Instead you have to change these lines:

     int x = 40+50, y = x, // dist from screen border

(50 is half of the width and therefore the difference between center and upper left corner)

Then you can delete

translate( 50, 50); // position each button at center of each cell

Regards, Chrisir

2 Likes

please note that the array (list) is an array of the objects derived from the class.

Each cell has its individual properties.

It is a grid on the screen but internally just a list.

There are also 2D arrays which can be seen as a grid data structure. See textual tutorials: Two dimensional arrays. (2D means grid here)

You can also read the text tutorial about array (1D = list)´and objects (class and objects)

here :

Button(float tempx, float tempy,

float tempw, float temph, 

color tempCol, 

float tempSz) {

we use

  • tempW and temph (w and h) in the class only in click();
  • sz only in display().

You might fix that.


This part is superfluent I guess:

    //checking for edges

    if (x+sz>=width)  

      x=width-sz-1;  

    if (y+sz>=height)

      y=height-sz-1;

Color :

You can make it more colorful using: color(random(255), random(255), random(255))

  myButtons [k] = new Button (
    x + i * (w + off), y + i2 * (h + off), 
    w, h, 
    color(random(255), random(255), random(255)), 
    random(50, 110)); // size

Click

Your mouse click doesn’t work anymore

    if (mouseX > x && 
      mouseX < x + w && 
      mouseY > y && 
      mouseY < y + h)

because it assumes that you don’t use rectMode(CENTER); !!!

This should work with rectMode(CENTER) :

  void click() {
    if (mouseX > x - w/2 && 
      mouseX < x + w/2 && 
      mouseY > y -h/2 && 
      mouseY < y + h/2) 
      on = !on; // toggle
  }
2 Likes

Hey @Chrisir
Thank you for clarifying my misunderstanding regarding adjusted placement. I see what you’re saying!!
:smile:

1 Like

Thank you @Chrisir!
Had read these text tutorials earlier and understand on a conceptual level. But may have an another question later as I try to add additional elements to this sketch…

1 Like

@Chrisir
It took me a while, but I finally got the buttons to work. I had to add +50 to the void click() if-statements in class code to adjust for the translate (50, 50) in the main program.

Now I am trying to add another (“seemingly simple”) element of interactivity with the background color. Background color to randomly change with mouse click.

After numerous approaches have landed on void mouseClicked() function. Though as appears in my current code is not working. Am I on the right track here? Or is there a better / simpler way to do this?

Code begins ////////////////////////////

int grid = 5, many = grid*grid; // cells per row and column, # in total

Button [] myButtons = new Button [many]; // declaring Button class array

int r1 = int(random(255));
int g1 = int(random(255));
int b1 = int(random(255));

int r2 = int(random(255));
int g2 = int(random(255));
int b2 = int(random(255));


void setup() {
  size (600, 600);

  int x = 40, y = x, // dist from screen border
    w = 100, h = w, off = 5; // width and height of one cell, dist btwn cells

  int k = 0; // counter for button objects in array
  for (int i = 0; i < grid; i++) { // counter for xpos on grid
    for (int i2 = 0; i2 < grid; i2++) { // counter for ypos on grid
      myButtons [k] = new Button ( x + i * (w+off), y + i2 * (h+off), 
        w, h, 
        int(random(255)), int(random(255)), int(random(255)), // random colors 
        random(50, 125)); // random sizes
      k++;
    }
  }
}
void draw() {

  background (r1, g1, b1);

  translate (50, 50);

  for (int i = 0; i < many; i++) 
    myButtons[i].display();
}

/*void mouseClicked(){ // I want to change background color when I click mouse...
 if (background == r1,g1,b1) {
 background = r2,g2,b2;
 } else {
 background = r1,g1,b1;
 }*/


void mousePressed() {

  //background(r2, g2, b2);

  for (int i = 0; i < many; i++) 
    myButtons[i].click();
}

////////////////////////////////////////////////////////

class Button {
  float x, y, w, h;
  color r;
  color g;
  color b;
  float sz;
  boolean on = false; // button starts in OFF position

  Button (float tempX, float tempY, float tempW, float tempH, 
    color tempR, color tempG, color tempB, float tempSz) {
    x = tempX;
    y = tempY;
    w = tempW;
    h = tempH;
    r = tempR;
    g = tempG;
    b = tempB;
    sz = tempSz;
  }

  void display() {
    if (on) {
      fill (r/2, g/2, b/2);
      noStroke();
    } else {
      fill (r, g, b);
      noStroke();
    }
    
    rectMode(CENTER);
    rect(x, y, sz, sz);  
  }

  void click() {
    if (mouseX > x - w/2 + 50 &&
      mouseX < x + w/2 + 50 &&
      mouseY > y - h/2 + 50 &&
      mouseY < y + h/2 + 50 )
      on = !on; // toggle on / off
      
  }
}

Any thoughts most welcome!!

1 Like

Hi Deb,

Translate(50,50) Question

Sorry for being unclear.

I try to repeat:

  • you can delete translate( 50, 50);

  • Instead you have to change these line: int x = 40+50, y = x, // dist from screen border - here you say + 50 as I did. Then this new x and y gets transferred into every object in your array.

  • in the function click() the if-statements in class code. No need to add 50 now because we fixed x and y with the last bullet point above. Besides: w and h is the full size of a cell. But we use only sz for the actual rect. So we might use sz/2 here (The half bit because the rectMode (CENTER) ). I did that now.

background question

Work with the variable type color for background and use a new variable named “background” to store the current background color.
Then you can check it with ==.

See below.

Regards, Chrisir



int grid = 5, many = grid*grid; // cells per row and column, # in total

Button [] myButtons = new Button [many]; // declaring Button class array

int r1 = int(random(255));
int g1 = int(random(255));
int b1 = int(random(255));

int r2 = int(random(255));
int g2 = int(random(255));
int b2 = int(random(255));

color background = color ( r1, g1, b1) ;  //!!!!!!!!!!!!!!!!!!!!!!!!


void setup() {
  size (600, 600);

  int x = 40 + 50, y = x, // dist from screen border  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    w = 100, h = w, off = 5; // width and height of one cell, dist btwn cells

  int k = 0; // counter for button objects in array
  for (int i = 0; i < grid; i++) { // counter for xpos on grid
    for (int i2 = 0; i2 < grid; i2++) { // counter for ypos on grid
      myButtons [k] = new Button ( x + i * (w+off), y + i2 * (h+off), 
        w, h, 
        int(random(255)), int(random(255)), int(random(255)), // random colors 
        random(50, 125)); // random sizes
      k++;
    }
  }
}
void draw() {

  background (background);  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  //  translate (50, 50); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  for (int i = 0; i < many; i++) 
    myButtons[i].display();
}


void mouseClicked() { 
  // I want to change background color when I click mouse...
  if ( background == color( r1, g1, b1) ) {  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    background = color(r2, g2, b2);
  } else {
    background = color(r1, g1, b1);
  }
}

void mousePressed() {

  //background(r2, g2, b2);

  for (int i = 0; i < many; i++) 
    myButtons[i].click();
}

//////////////////////////////////////////

class Button {
  float x, y, w, h;
  color r;
  color g;
  color b;
  float sz;
  boolean on = false; // button starts in OFF position

  Button (float tempX, float tempY, 
    float tempW, float tempH, 
    color tempR, color tempG, color tempB, 
    float tempSz) {
    x = tempX;
    y = tempY;

    w = tempW;
    h = tempH;

    r = tempR;
    g = tempG;
    b = tempB;
    sz = tempSz;
  }

  void display() {
    if (on) {
      fill (r/2, g/2, b/2);
      noStroke();
    } else {
      fill (r, g, b);
      noStroke();
    }

    rectMode(CENTER);
    rect(x, y, sz, sz);
  }

  void click() {
    if (mouseX > x - sz/2  &&   // !!!!!!!!!!!!!!!!
      mouseX < x + sz/2  &&
      mouseY > y - sz/2  &&
      mouseY < y + sz/2  )
      on = !on; // toggle on / off
  }
}
1 Like