Search code examples
javaappletcustom-painting

java.awt.Graphics.fillRect() misbehaving


Below I have a simple method for painting a set of objects onto an java.awt.applet.Applet. I thought this was very straightforward, but it ends up only painting the objects as a single pixel at the top-left corner of the applet. The idea is that the Display class takes in a set of fairly lightweight objects that extend GameObject and contain information about their location, size, and appearance on the screen, and then draws them pixel-by-pixel onto the applet, stretching and positioning them proportionally depending on the specified display height and width. In testing this, I set the width and height of the Display to 128, and pass two objects to the Display, which are both 32-pixel squares (both return 32 for getWidth() and getHeight()), one is red and returns 24 for getX() and getY(), and the other is blue and returns 16 for getX() and getY(). I put the Display in a javax.swing.JFrame and use a java.awt.BorderLayout to ensure it fills the frame (I use add(display, java.awt.BorderLayout.CENTER); within the aforementioned javax.swing.JFrame).

As far as I can tell, this should be paining a blue 32-pixel square that's 16 pixels from the top and left edges and a red 32-pixel square that is either obscured by or obscuring part of the other one. However, all I get is a single red or blue pixel in the top-left corner of the Display. This is consistent no matter how big or small the window is.

Code


public class Display extends java.awt.applet.Applet
{
  private int w,h;
  private ArrayPP<GameObject> gameObjects;//ArrayPP is my way of making a dynamically expanding array. It is similar to Vector, but has many more useful methods I use elsewhere.

  public Display(int width, int height)
  {
    w = width;
    h = height;
  }

  public void addGameObject(GameObject go)
  {
    gameObjects.add(go);
  }

  public void refresh(java.awt.Graphics g)
  {
    int x, y, w, h;
    final int W = getWidth(), H = getHeight();
    for (GameObject go : gameObjects)//Draw all objects
      for (x = go.getX(), y = go.getY(), w = go.getWidth() + x, h = go.getHeight() + y; y < h; y++)//Draw all lines of the object
        for (x = go.getX(); x < w; x++)//Draw all the pixels on this line of the object
        {
          g.setColor(go.getColorForPixel(x, y));
          g.fillRect((x / this.w) * W, (y / this.h) * H, w/W, h/H);
        }
  }
}

 

public interface GameObject
{
  public int getX();
  public int getY();
  public int getWidth();
  public int hetHeight();
  public java.awt.Color getColorForPixel(int x, int y);
}

Question


Why is java.awt.Graphics.fillRect(int x, int y, int width, int height) only painting the topleft corner of the applet?

Solution


The solution lies in the line that reads

          g.fillRect((x / this.w) * W, (y / this.h) * H, w/W, h/H);

wherein integer calculations cause all values to be 0. The solution is as follows:

          g.fillRect((int)(((float)x/(float)this.w) *W),
                     (int)(((float)y/(float)this.h) *H),
                     (int)((float)W/(float)w),
                     (int)((float)H/(float)h));

Solution

  • The problem lies with

    (x / this.w) * W
    

    If x and this.w are both integers and x

    Convert one or more of x and w to float to force a floting point division.

    (int)(((float)x/(float)this.w) *W)