0

I am a beginner with Java and especially Java Swing. What I am trying to do is create randomly generated "buildings" (which I have done) and on top of them add windows in rows/columns that are equally sized and spaced apart. However I want to do this in a loop (for loop?). My end goal is to also only have a few of the windows light up each time (this also being randomly generated) the code is run. Here is what I have so far, the window I have created is basically the size I want them to be. I know my attribute maxX is not used but I have created it to remind me of the max X value and in case I need it later.

import java.awt.*; 
import javax.swing.*;
public class JPanelExample extends JPanel 
{     
  private int maxX = 784;
  private int maxY = 712;
  @Override 
  public void paint(Graphics g) 
  { 
    Graphics2D g2d = (Graphics2D) g;
    g2d.setColor(Color.WHITE);
    g2d.fillRect(5, 5, 25, 25);
    int width = (int)(Math.random()*100+100);
    int height = (int)(Math.random()*350+100);

    for (int i =10; i<634; i+=(width+10))
    {
      for (int j = 462 ; j>=462; j--)
      {

        g2d.setColor(Color.GRAY);
        g2d.drawRect(i, maxY-height, width, height);
        g2d.fillRect(i, maxY-height, width, height);
        g2d.setColor(Color.YELLOW);

        g2d.drawRect(i+5, (maxY-height)+5, width/6, width/6);
        g2d.fillRect(i+5, (maxY-height)+5, width/6, width/6);

        height = (int)(Math.random()*462+100);

        while (width == i+(width+10))
        {
          width = (int)(Math.random()*100+100);
        }
      }
    }
  }
  public static void main(String[] args) 
  { 
    JFrame frame = new JFrame("Frame"); 
    frame.add(new JPanelExample());
    frame.setBackground(Color.BLACK);
    frame.setSize(800, 750); 
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  }
}
Sam Mitchell
  • 194
  • 2
  • 18
  • 1
    Don't override `paint`, use `paintComponent` instead, also make sure you call `super.paintComponent` in order to maintain the paint chain. See [Painting in AWT and Swing](http://www.oracle.com/technetwork/java/painting-140037.html) and [Performing Custom Painting](http://docs.oracle.com/javase/tutorial/uiswing/painting/) for more details – MadProgrammer Nov 08 '15 at 04:02
  • @MadProgrammer so you mean where I have `paint(Graphics g)` instead have `paintComponent(Graphics g)`?, and delete the override? Where would I call `super.paintComponent`? – Sam Mitchell Nov 08 '15 at 04:10
  • `paintComponent` is a method defined in `JPanel` (actually one it's parents), just like `paint`. So yes, where it says `public void paint(Graphics g)`, replace it with `protected void paintComponent(Graphics g)` instead. You call `super.paintComponent` before you do any custom painting (inside `paintComponent`) – MadProgrammer Nov 08 '15 at 04:16
  • @MadProgrammer Ok thanks, not at my PC anymore but will change this tomorrow. Do you have any ideas on how to achieve the "window" issue? – Sam Mitchell Nov 08 '15 at 04:46

2 Answers2

1

I hope you're having fun with Java and if you're still looking for an answer (though there are many) here's my suggestion:

In order to get a row of windows on the buildings you've drawn here, you need to know:

  • how many windows you'll be drawing (from your code, it looks like you always want 6 windows)
  • where to begin drawing (from your code, this seems to be 5px after the start of each building
  • how much spacing between windows you want (this isn't evident in your code, but it can be whatever you want -- for this example we will use 5px again)
  • what colour the window should be (for this example we will use white for no-light and yellow for light turned on).

Set Up

We can store all these numbers in variables like this (using values from your code):

// for the lights:
Color off = Color.WHITE;
Color on = Color.YELLOW;

// for window calculations
int space = 5;
int startx = i+space;
int starty = maxY-height+space;
int interval = (width-space)/6;

Note that we subtract one space from the building's width before dividing by 6 to discount the initial space before the first window. I'm sure you've seen this already, but drawing diagrams can also be very helpful when starting with Java/Swing

The Loop

We can now loop through the number of windows you'd like to place in that row of windows. In this case, it looks like you'll want 6 windows every time. For each window (inside the for-loop) we first want to decide on the color (in the example we use a 10% chance of the lights being on, as noted below). Once we've set the colour, we simply use the values we've noted above to fill the next window rectangle, which is explained below. Make sure your for-loops have different variable names, since we have them nested here

for(int k = 0; k < 6; k++) {
    if((int)(Math.random()*100) < 10) //10% of the time, turn the light color on
        g2d.setColor(on);
    else 
        g2d.setColor(off);

    //g2d.drawRect(i+5, (maxY-height)+5, width/6, width/6);
    g2d.fillRect(startx+(k*interval), starty, (interval)-space, (interval)-space);
}

As a note: the drawRect followed by fillRect here are redundant. I'm not sure if you have a specific purpose for drawing the rect first (in which case, ignore this), but view your app with the drawRect commented out to see what it does.

If you have any trouble with the Math.random function here, check out these resources:

http://docs.oracle.com/javase/7/docs/api/java/lang/Math.html

Math.random() explained

Exploring the fillRect in our example:

fillRect takes a few variables noted below (details at: http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics.html)

fillRect(int x, int y, int width, int height)

In our example we've set the following:

x = startx + (k * interval) , k being the incremental variable for the for loop (runs from 1 .. 6), increasing the x value for the rectangle by a window's interval after each window drawn.

y = starty , this is consistent for each row.

width, height = interval - space , this sets the dimensions of the window and ensures a proper space before the next window.

This should give you a working 1 row of windows.

Columns

Getting columns of windows is very similar to getting the row. There are many ways to do all of these things, but I'll briefly go through another nested-for-loop.

In order to get columns of windows we need to know:

  • How many rows you want to have (how many windows per column)

Because we've already set up window dimensions we can determine the number of windows that can fit in a column using the following:

int num_rows = (height - space) / interval;
//and to set a maximum number of rows to a column (ex: 6)
int num_rows = Math.min(((height-space) / interval), 6); //a max number can replace 6 here

Here we'll use another for-loop to continuously add rows, num_rows times. Note: we've changed fillRect such that y = starty + (l*interval) , incrementing the start position y to the next location of rows each time one row is drawn.

for(int l = 0; l < num_rows; l++){
    for(int k = 0; k < 6; k++) {
        if((int)(Math.random()*100) < 10) //10% of the time, turn the light color on
            g2d.setColor(on);
        else 
            g2d.setColor(off);

        g2d.fillRect(startx+(k*interval), starty + (l*interval), (interval)-space, (interval)-space);
    }
}

And that's that. Hope that's helpful and not too confusing.

Community
  • 1
  • 1
K.F
  • 459
  • 3
  • 12
  • So I saw this after spending hours on my code and redesigning it. I figured out a way on my own actually. However, as I am new to Stack Overflow, do I post my solution as an update? I have encountered a new issue if you would like to check [that](http://stackoverflow.com/questions/33642097/repainting-an-instance-of-a-class-from-an-arraylist) out? – Sam Mitchell Nov 11 '15 at 00:18
  • Hello, yes, it would be helpful if you post your solution and mark the question solved so that anyone having related questions can use it as a reference/resource. (And of course I'd be happy to look at your new issue just now) – K.F Nov 11 '15 at 00:23
0

After a long time, I figured out a solution. I have changed the for-loop to this:

   for (int i =10; i<634; i+=(a+10))//buildings
{

  g2d.setColor(Color.GRAY);
  g2d.drawRect(i, maxY-height, width, height);
  g2d.fillRect(i, maxY-height, width, height);


  rows = Math.round((height)/25);
  columns = Math.round(width/25);

  for (int j = 1; j<=columns; j++)//windows
  {
    for (int k = 1; k<=rows; k++)
    {
      g2d.setColor(Color.BLACK);
      g2d.drawRect(i+5*j+20*(j-1), (maxY-height)+5*k+20*(k-1), 20, 20);
      if (Math.random()<0.7)
      {
        g2d.setColor(Color.YELLOW);
        g2d.fillRect(i+5*j+20*(j-1), (maxY-height)+5*k+20*(k-1), 20, 20);
      }
      else
      {
        g2d.setColor(transYellow);
        g2d.fillRect(i+5*j+20*(j-1), (maxY-height)+5*k+20*(k-1), 20, 20);
        g2d.setColor(transYellow);
        g2d.fillRect(i+5*j+20*(j-1), (maxY-height)+5*k+20*(k-1), 20, 20);
      }
    }
  }

  addBuilding();
  a = width;
  height = (int)(Math.random()*462+100);
  width = (int)(Math.random()*100+100);

}
Sam Mitchell
  • 194
  • 2
  • 18