The problem I'm working on is to draw a brick wall where each row of bricks is offset from the row above and below. I'm trying to follow examples in the text which use loops and conditions but I've really gotten confused. I'm not quite sure I know how to set this up and how to set the frame size to display everything that has been drawn.
When I run this I just get a small window showing a partial brick and if I expand the window manually the column of bricks extends below but it looks like they go on infinitely. If anyone can help this is what I've stumbled through so far.
Code:
public class BrickWall
{
//---------------------------------------
// Creates the main frame of the program
//---------------------------------------
public static void main(String[] args)
{
JFrame frame = new JFrame ("Brick Wall");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
BrickWallPanel panel = new BrickWallPanel();
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
Code:
import javax.swing.JPanel;
import java.awt.*;
public class BrickWallPanel extends JPanel
{
private final int NUM_BRICKS = 25;
private final int LENGTH_BRICK = 50; // max length of a brick
private final int WIDTH_BRICK = 20; // max width of a brick
private int length, width; // length and width of the frame
//---------------------------
//Sets up the drawing panel
//---------------------------
public BrickWallPanel()
{
length = LENGTH_BRICK; // assign length of brick
width = WIDTH_BRICK; // assign width of brick
setPreferredSize (new Dimension (length, width));
setBackground (Color.darkGray);
}
//------------------------------------------------------
// draws the bricks across the frame and down the frame
//------------------------------------------------------
public void paintComponent (Graphics page)
{
super.paintComponent(page);
int x, y; // x and y of the brick
x = 0; // initial x of the first brick
y = 0; // initial y of the first brick
for (int countY = 0; countY <= width; countY++) // draws the columns
{
for (int countX = 0; countX <= length; countX++) // draws the rows
{
if (x % 2 == 0)
{
page.setColor (Color.red);
page.fillRect (x/2, y, LENGTH_BRICK, WIDTH_BRICK);
x = x + 52;
x = 0;
y = y + 22;
}
else
page.setColor (Color.red);
page.fillRect (x, y, LENGTH_BRICK, WIDTH_BRICK);
x = x + 52;
}
x = 0;
y = y + 22;
}
}
}
Sorry, I have to run somewhere so I can't explain what I did. I will be back in a couple hours if you want to post a follow-up question, or someone else will help you.
Here is a modified version of your code with some comments.
Code:
import javax.swing.JPanel;
import java.awt.*;
public class BrickWallPanel extends JPanel
{
private final int WIDTH_BRICK = 50; //brick width
private final int HEIGHT_BRICK = 15; //brick height
//---------------------------
//Sets up the drawing panel
//---------------------------
public BrickWallPanel()
{
//size of window
setPreferredSize (new Dimension (500, 500));
setBackground (Color.darkGray);
}
//------------------------------------------------------
// draws the bricks across the frame and down the frame
//------------------------------------------------------
public void paintComponent (Graphics page)
{
super.paintComponent(page);
//the x and y offset of the brick, so I'm
//not drawing a brick within another brick
int xOffset, yOffset;
yOffset = 0; // initial y of the first brick
for (int countY = 0; countY <= WIDTH_BRICK; countY++) //rows
{
//new row, so reset the x offset
xOffset = 0;
for (int countX = 0; countX <= HEIGHT_BRICK; countX++) //columns
{
page.setColor (Color.red);
page.fillRect (countX + xOffset, countY + yOffset, WIDTH_BRICK, HEIGHT_BRICK);
xOffset += WIDTH_BRICK;
}//end for
yOffset += HEIGHT_BRICK;
}//end for
}//end paint
} //end class
Let me just run through this to see how it's working a little.
So, for the first row, the location of the first brick is going to be at (countX + xOffset) which is 0, (countY + yOffset) which is 0 and WIDTH_BRICK which is 50 and HEIGHT_BRICK which is 15. For the 2nd Brick (countX + xOffset)16 (countY + yOffset)0 and WIDTH_BRICK 50 and HEIGHT_BRICK 15, the loop continues while countX is less than HEIGHT_BRICK.
Once countX is greater than HEIGHT_BRICK we exit that loop and increment the yOffset counter and test the condition for the outerloop. countY = 1 which meets the condition of being less than WIDTH_BRICK, so we enter the loop again. XOffset is set to 0 again and we enter the inner for loop. For the second row, the location of the first brick is going to be at (countX + xOffset) which is 0, (countY + yOffset) which is now 16, and WIDTH_BRICK 50 and HEIGHT_BRICK 15. The xOffset is incremented the width of the brick and countX is incremented by 1. This changesthe x coordinate for the next brick on the next run through.
So, doing like this, the bricks still align perfectly, so we have to figure out how to get the even numbered rows to offset by half a brick so the columns don't line up evenly?
Is there any way to set up the Window size to match the size of the Graphics being drawn? It seems like an arbitrary value setting dimensions to 600,600?
Code:
setPreferredSize (new Dimension (600, 600));
Thanks this has helped.
Last edited by Blue1974; Mar 11th, 2010 at 08:52 PM.
And once we modify the offset, I'm not sure how the alignment will work, but for now, since you're using constants, you can set the size of the window using the following formula.
Sort of idea? If that is the case, you can accomplish this with 2 IF statements. I have the code if you need to see it, but the logic is as follows, and the above sizing will work with the new grid as well.
If you're on a row divisible by 2 and a column divisible by 2, you need to draw a brick, otherwise, if you're on a row not divisible by 2 and a column not divisible by 2, then you need to draw a brick.
Last edited by kfcSmitty; Mar 11th, 2010 at 10:40 PM.
Thanks, with regard to the setPreferredSize of the window that is what I was trying to do but didn't know how.
Now, with the condition to alternate the way each row of bricks is displayed. I would put the condition within the inner loop. Something like this?????
I'm not sure if that's what you were trying to tell me. Would there be a way to get the half brick in the wall on the even rows before it shifts over to put in a full brick?
Thanks for helping me with this. I'm having a hard time with these loops. It's hard for me to visualize these unless I just walk through it slowly like I was trying to do at the top. I amazed at how programmers keep can visualize these and put them together.
Last edited by Blue1974; Mar 11th, 2010 at 11:26 PM.
I'm not exactly sure what you mean, and your code is very close. You're missing the opening brace for your if and else.
When you leave out the braces {}, from your if and else, they will only see the first line after it.
ie
Code:
if (x == 1)
System.out.println("1!");
else
System.out.println("Not one!");
//will work
If you had two lines, it would have to be
if(x==1){
System.out.println("line 1");
System.out.println("line2");
}else{
System.out.println("else1");
System.out.println("else2");
}
You're also missing the braces for your for loop.
Is this what you're attempting to accomplish?
Code:
import javax.swing.JPanel;
import java.awt.*;
public class BrickWallPanel extends JPanel
{
private final int WIDTH_BRICK = 40; //brick width
private final int HEIGHT_BRICK = 15; //brick height
//---------------------------
//Sets up the drawing panel
//---------------------------
public BrickWallPanel()
{
//size of window
setPreferredSize (new Dimension ((WIDTH_BRICK * HEIGHT_BRICK) + (WIDTH_BRICK + HEIGHT_BRICK), (WIDTH_BRICK * HEIGHT_BRICK) + (WIDTH_BRICK + HEIGHT_BRICK)));
setBackground (Color.darkGray);
}
//------------------------------------------------------
// draws the bricks across the frame and down the frame
//------------------------------------------------------
public void paintComponent (Graphics page)
{
super.paintComponent(page);
//the x and y offset of the brick, so I'm
//not drawing a brick within another brick
int xOffset, yOffset;
yOffset = 0; // initial y of the first brick
for (int countY = 0; countY <= WIDTH_BRICK; countY++) //rows
{
//new row, so reset the x offset
xOffset = 0;
for (int countX = 0; countX <= HEIGHT_BRICK; countX++) //columns
{
if(!(countX % 2 == 0) & !(countY % 2 == 0)){ //odd row and odd column
page.setColor (Color.red);
page.fillRect (countX + xOffset, countY + yOffset, WIDTH_BRICK, HEIGHT_BRICK);
}else if((countY % 2 == 0) & (countX % 2 == 0)){ //even row and even column
page.setColor (Color.red);
page.fillRect (countX + (xOffset - (WIDTH_BRICK/2)), countY + yOffset, WIDTH_BRICK, HEIGHT_BRICK);
}//end if
xOffset += WIDTH_BRICK;
}//end for
yOffset += HEIGHT_BRICK;
}//end for
}//end paint
}//end class
Sorry, I haven't done a better job of describing this. I tried your code and it looks interesting. The brick columns sort of look like zippers, but no, that's not quite the appearance I was trying to get. I liked your analogy previously, about brick space brick and on the next row down space brick space. It's just that the space is minimal. It needs to be a half brick moved over or staggered if that word makes sense in this case. I think if the index row is even I want to try to paint a brick a half brick length to the left. I'm just not quite sure how to set it up. I can't set the xOffset to a negative number, like subtracting half the length of the brick from 0 and to begin drawing at that point. Thanks for you input on this.
Yes, that's it! I think you had it previously but it didn't look like the half bricks would get printed on the even rows where you move over to draw the first full brick.
Also, thanks for your correction on my use of the braces. I understand now I should have used them to enclose what the condition included.
It's saying if countX % 2 does not equal 0 and countY % 2 does not equal 0 then do the operation in the brackets. Is your logical and suppose to be two ampersands &&. It shows it like that in my text but maybe one still works? I'll go back and try them.
then for the else which looks for the even rows:
It's saying if countX % 2 does equal 0 and countY % 2 also equals 0 then perform the code in the braces.
Code:
else if((countY % 2 == 0) & (countX % 2 == 0)){ //even row and even column
page.setColor (Color.red);
page.fillRect (countX + (xOffset/2), countY + yOffset, WIDTH_BRICK, HEIGHT_BRICK);
}
Where did you change the postion for painting a brick when it's an even row? It's staring me in the face but I'm not seeing it.
As for changing the position for paining the brick, it is actually the if statement that does the calculation on when to draw the brick.
If the row is even and the column is even, then draw a brick, otherwise if the row is odd and the column is odd, draw the brick. It will not draw a brick if the row is odd and the column is even or vice versa.
Since the two operations are opposite, they will stagger the bricks in this instance.
For example: the below code with a slightly modified condition still has opposite statements, but gives the same result.
Code:
if((countX % 2 == 0) && !(countY % 2 == 0)){ //odd row and odd column
page.setColor (Color.red);
page.fillRect (countX + (xOffset/2), countY + yOffset, WIDTH_BRICK, HEIGHT_BRICK);
}else if((countY % 2 == 0) && !(countX % 2 == 0)){ //even row and even column
page.setColor (Color.red);
page.fillRect (countX + (xOffset/2), countY + yOffset, WIDTH_BRICK, HEIGHT_BRICK);
}//end if
So I'm not actually modifying the location of the brick to stagger it, I am simply not drawing it unless it is in a staggered position.
I'm confused at how the loop is working. I can see that in the conditional that your identifying if the row is even and the column is even and when the row and column are not even that's when you paint the brick Ok, so there doesn't have to be an else to cover the alternative when the row is even and column is odd or when the column is odd and the row is even it will just run through the statements and it gets to the bottom and then counter is incremented.
Ok, I think I kind of have it but it is confusing for me. I wouldn't have figured this out without the help.
I think what I was trying to see was one of the conditions painting the brick differently than the other. If it doesn't meet this criteria then paint it with these specifications. I think that's why I'm having a hard time getting this. I was looking at the code executed for each of the conditions and they were identical.
It sounds like you're getting it. No matter what I want to draw the brick at the same place, but there are only 2 conditions when I want to draw it. If I draw it when the conditions were false, then it would fill in all the gaps.
Maybe this will make more sense to you. You could also write the if like this, to avoid the duplicate code.
Code:
if((!(countX % 2 == 0) && !(countY % 2 == 0)) || ((countY % 2 == 0) && (countX % 2 == 0))){ //odd row and odd column OR even row and even column
page.setColor (Color.red);
page.fillRect (countX + (xOffset/2), countY + yOffset, WIDTH_BRICK, HEIGHT_BRICK);
}//end if
I just tried to avoid the long if incase it confused you, but this way shows that I am indeed drawing the brick the same every time. The for loop is what creates the spacing and the condition says when to draw it so you get the proper pattern.
I do like that combined IF statement it puts all the condtions in one place. I kept thinking that if the conditions weren't met then you needed an ELSE to deal with the alternative but you don't need the else.
I know you worked hard on trying to explain this to me. Again, thanks for spending the time on this.