# Thread: for loops, GLines and a bothersome expression

1. ## for loops, GLines and a bothersome expression

this code is supposed to draw hierarchy type diagram depending on the levels and the subboxes for each heirarchy which, are given as constants.
i should be able to change the constants and the program should still work. but it only works when there are <3 levels or subboxes is 1

I cannot get the GLines in the right place after the first group in on the levels two or more down.

i have tried plotting the points and drawing the Gline back to the level above but came accross a similar difficulty

the problem expression is at line:43
i need to add something to this expression (possibly, something multiplied by the the index of the second loop 'k') because when K is 0 it does it correct.

the objective of this exercise was start understanding how to write methods and maybe the problem is therein, I have used the boxesInRow method to predict where the next row of boxes will be by passing it the index value of the first for loop plus 1 i.e 'i+1'

I dont want to use arrays or other stuff that i havent yet learned about to solve the problem, if it cannot be done with simple programming techniques then fair enough but please explain why

even if you dont know how to solve the expression issue, if you can show me some ways that i can write better methods to solve this problem then great
any help is gratefully accepted, thanks in advance
Sonny

heres the code:
Java Code:
```/*File  Hierarchyb.java
* this program draws hierarchy diagrams.
* objects are equally centred in vertical
* objects are equally spaced in the horizontal.
* note the difference between equally centred and equally spaced.
* GLines from the centres of the edges of GRects
* Assignment #2: CS106a Simple Java Programs
* Programming exercise 3
*
*/

import acm.program.*;
import acm.graphics.*;
public class Hierarchyb extends GraphicsProgram {

private static final int HEIGHT = 10;
private static final int WIDTH = 30;
private static final int LEVELS = 3;
private static final int SUBBOXES = 3;

public void run(){
int scrW = getWidth();
int scrH = getHeight();
double ySpace = scrH/(LEVELS+1);	//spacing between centres of levels
for (int i=0;i<LEVELS;i++){
double boxInRow=boxInRow(i); // calls method and assigns result
double plotY = i*ySpace+ySpace; // plots y
double nextY = plotY+ySpace; // plots next Y (to draw GLines to)
double xSpace = xSpace(scrW,boxInRow); // calls method assigns result.
int j = 1;
for(int k=0;k<boxInRow;k++){
double plotX = ((k*xSpace+xSpace)+(j*(WIDTH/2)));
GRect box = textBox(plotX,plotY);
GLabel label = boxLabel(plotX,plotY);
int kk=k;
int jj=j;
if(i!=LEVELS-1){
for (int l = 0; l<SUBBOXES;l++){
double boxNext = boxInRow(i+1);
double nextXspace = xSpace(scrW,boxNext);
/*>problem expression>*/double nextX = (kk*nextXspace+nextXspace)+(jj*WIDTH/2);  // plots the next X(to draw line to)
//pause(100);
jj+=2;
kk+=1;
}
}
j+=2;
}
}
}
/* determines the space between boxes so they can be equally spaced along the row*/
private double xSpace(int scrW, double boxInRow) {
double result = ((scrW -(boxInRow*WIDTH))/(boxInRow+1));
return result;
}
/* determines boxes in row based on the index of the first for loop*/
private int boxInRow (int i){
int boxes = 1;
for (int a=0;a<i;a++){
boxes*=SUBBOXES;
}
return boxes;
}

private GRect textBox (double x, double y){
GRect textBox = new GRect(x-WIDTH/2,y-HEIGHT/2,WIDTH,HEIGHT);
return textBox;
}
private GLabel boxLabel (double x, double y){
GLabel boxLabel = new GLabel("O");
boxLabel.setLocation((x-boxLabel.getWidth()/2), ((y-2)+boxLabel.getAscent()/2));
return boxLabel;

}
}```

2. ## What a mess I made of that!

okay, okay, now I am starting to get my head around methods and have re written this code. but i still cant get around the Glines bit.

in the first code i posted (above)there is definitley a bug with the indexing, which i think has something to do with integer division. and maybe thats why i cant predict the nextX accuratley. I think I have overcome the indexing problem with the code (below) But the problem still exists how to draw a GLine to either
1. a point that i havent plotted yet, but am going to plot on the next iteration of the for loop.
2 draw a line back to point I have already plotted bit is no longer in any current stack frame.

at least i think thats what the problem is!

perhaps there is no way round this problem without creating another class( which i dont know how to do yet, until i complete the next few chapters of my book and watch the next few lectures) so unless some real clever clogs can come up with or guide me to a solution to this problem using a single class and private methods, i am putting this baby to bed content that I have at least manged to rewrite the code that draws the boxes using a JAVA methodology rather than the BASIC/procedural approach that i started out with.
And also thanks to a few ppl in here that helped me with writing methods with some of my other exercises, that was a big help.

so heres the code that does just the boxes and labels.
any last thoughts suggestions or advice welcomed...
but i wont hold my breath!! :D eventhough if you're still reading at his point you must be
A. really up a challenge or;
B. a really sad Billy no Mates with nothing better to do!:D or
C stuggking eith methods like me

Java Code:
```import acm.program.*;
import acm.graphics.*;
public class Hierarchyb extends GraphicsProgram {

private static final int HEIGHT = 40;
private static final int WIDTH = 160;
private static final int MIN_BOX_WIDTH=10;
private static final int LEVELS = 4;
private static final int SUBBOXES = 4;

public void run(){
beginBoxLayout( getHeight()/(LEVELS+1) );
}

/* determine Y coordinates for each row with a for loop
* calls boxesInRow method as a parameter of the setOutBoxes method call*/
private void beginBoxLayout(double y) {
for (int i = 0; i < LEVELS; i++){
setOutBoxes (boxesInRow(i), y*i+y);
}
}

/* determine the number of boxes in a row based on value of index(i) in the beginBoxLayout method */
private int boxesInRow (int index) {
int numBoxes = 1;
for (int i = 0; i < index; i++){
numBoxes*=SUBBOXES;
}
return numBoxes;
}

/* receives the numBoxes and y coordinate for the plot
* calls adjust boxWidth, calls equallySpaceBoxes,
* begins next for loop, plots the x location
private void setOutBoxes (int numBoxes, double y) {
int boxWidth = adjustBoxWidth (numBoxes, WIDTH);
double spaceBetweenBoxes = equallySpaceBoxes (numBoxes, boxWidth);
for (int i = 0; i < numBoxes; i++){
double x = (i * boxWidth) + ( (i+1) * spaceBetweenBoxes) + (boxWidth/2);
textBox (x, y, boxWidth);
boxLabel (x, y);
}
}

/* determines the space between boxes so they can be equally spaced along the row*/
private double equallySpaceBoxes (int numBoxes, int boxWidth) {
double spaceBetweenBoxes = ( (getWidth()-(numBoxes * boxWidth) )/( (double)numBoxes+1) );
return spaceBetweenBoxes;
}

/* checks the number of boxes multiplied by WIDTH is less than screen width
* if true the box width remains unchanged,
* if false the box width is reduced by 5 pixels and the method
* is called recursively (to a minimum of 10 pixels).
*/
private int adjustBoxWidth(int numBoxes, int boxWidth) {
if(boxWidth < MIN_BOX_WIDTH ) return MIN_BOX_WIDTH;
if(numBoxes * boxWidth <= getWidth() )return boxWidth;
return adjustBoxWidth (numBoxes , boxWidth-5 );
}

private GRect textBox (double x, double y, int boxWidth){
GRect textBox = new GRect(x-boxWidth/2,y-HEIGHT/2,boxWidth,HEIGHT);
return textBox;
}

private GLabel boxLabel (double x, double y){
GLabel boxLabel = new GLabel("O");
boxLabel.setLocation( (x-boxLabel.getWidth()/2) , ( (y-2) + boxLabel.getAscent() / 2) );
return boxLabel;
}
}```

3. Senior Member
Join Date
Mar 2010
Posts
952
Rep Power
7
I haven't forgotten this, Sonny. The trouble is, by drawing your GRects in a for loop like this, and not keeping any references to them, you make it very difficult to figure out the relationships you need to draw your GLines from one to another. You could call getComponents() which would return an array of all the Components on the page, figure out which ones are your GRects, and go from there, but it would be ugly. Better to keep track of them as you're putting them on the page, but even that is not easy with your current design.

For example, if you store them in a simple "ArrayList<GRect> boxes", you know that boxes[0] needs to connect to boxes[1]..boxes[4]. Then boxes[1] needs to connect to boxes[5]..boxes[8], boxes[2] needs to connect to boxes[9]..boxes[12], etc. Finally, boxes[5] needs to connect to boxes[21]..boxes[24], etc. and boxes[20] needs to connect to boxes[81]..boxes[84]. So, let's see, childBoxIndex = parentBoxIndex * 4 + offset (1..4)? Is it really that simple? Looks like maybe it is. So once you have the two GRects, it's not too difficult to find the parentConnectorPoint (x + getWidth() / 2, y + BOX_HEIGHT) and the childConnectorPoint (x + getWidth() / 2, y), and then you can draw your GLine. I just implemented it in your code, and it works.

-Gary-

4. Senior Member
Join Date
Mar 2010
Posts
952
Rep Power
7
By the way, if you want to discuss doing this in a more object-oriented fashion, let me know, because I have some ideas and I think it makes a good exercise. I know you're doing the Stanford CS106A iTunes U course. I'm thinking of going back through the assignments and handouts and doing them in AWT and/or Swing rather than using the ACM libraries. It's considerable work, but it may be worthwhile.

-Gary-

5. thanks Gary,
i'm going to come back to this once i have covered a bit more of the course.
arrays is a few chapters off yet.

I did solve the original heirarcy task in assignment 2 which is simpler by definition, but i always like to try and develop the Assignments and text book programming exercises a little further. but i ended up chasing my tail with this one..

kind regards
Sonny