Problem with Graphics/Graphics2D

Hey, I’m trying to make a simple program that renders a bunch of squares on a JPanel. It isn’t a game in of itself, but more of a base for some game stuff I want to do. Unfortunately, I’m having some really weird graphical glitches when I run it, and I was wondering if yalls had any suggestions.

Here is the relevant code I have:

public class Game
{
	public static GUILayer GUI;
	public static DataLayer data;
	public static LogicLayer logic;
	
	public static void main(String[] args)
	{
		GUI = new GUILayer();
		data = new DataLayer();
		logic = new LogicLayer();
	}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JFrame;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class GUILayer extends JPanel
{
	public static final int TILE_WIDTH = 20;
	public static final int GAP_WIDTH = 2;
	public static final Color GAP_COLOR = new Color(61, 131, 196);
	public GUILayer()
	{
		this(800,600);
	}
	public GUILayer(int width, int height)
	{
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(width, height);
		frame.setVisible(true);
		frame.setResizable(false);
		frame.setLocationRelativeTo(null);
		frame.add(this);
	}
	
	public void draw(Graphics g) //I think this is the function that is acting up.
	{
		//Draw the tiles
		Graphics2D g2d = (Graphics2D)g.create();
		//Calculate the dimensions of the tile
		int rectWidth = TILE_WIDTH + 2 * GAP_WIDTH;
		//Render the grid of tiles
		for(int i = 0; i < Game.data.getTileArray().length; i++)
		{
			for(int q = 0; q < Game.data.getTileArray()[0].length; q++)
			{
				g2d.setColor(GAP_COLOR);
				g2d.drawRect(i * rectWidth, q * rectWidth, rectWidth, rectWidth);
				g2d.setColor(Game.data.getTileArray()[i][q].getColor());
				g2d.drawRect(i * rectWidth + GAP_WIDTH, q * rectWidth + GAP_WIDTH, TILE_WIDTH, TILE_WIDTH);
			}
		}
	}
}
public class LogicLayer
{	
	public LogicLayer()
	{
		//I think that this bit may be part of the problem.
		
		//Tell the GUI layer to draw the tiles.
		Game.GUI.draw(Game.GUI.getGraphics().create());
	}
}

At the moment, all this program does is create a blank screen. I’m pretty sure that the problem is either in the LogicLayer’s constructor, or in the GUILayer.draw() function. At one point I was able to get the entire grid to render, and occasionally I get part of it, so I don’t think that it is the code that actually does the rendering or that sets up the JFrame.

I think it could be where I create the graphics object and call draw(), but I’m not sure. Graphics/Graphics2D objects are still a bit of a mystery to me. At any rate, I’d really appreciate any advice you may have.

  1. Graphics2D g2 = (Graphics2D)g; is sufficient, a graphic2d context has not to be instanciated everytime in that way, java will decide.
  2. JPanel are JComponent, and therefore will require to be painted alike. draw() must be implemented in the protected void paintComponent(Graphics) function while the LogicLayer will call either repaint() (for passive rendering) or Jpanel.update(Jpanel.getGraphics()) for active rendering.
    This is because Swing is required to be involved for repainting for the Java2D overlay gets lost with peer sync and edthread.

[quote] Graphics/Graphics2D objects are still a bit of a mystery to me.
[/quote]
Graphics is simply an object that give you a cupple of methods to perform drawing/painting witout knowing the exact underlying target format.

Graphics2D extends Graphics

AWT/Swing methode often return Graphics rather than Graphics2D object (for some old internals compatibilities reasons) but it will be often a Graphics2D instance that’s why you can safely do things like :

Graphics2d g2=(Graphics2D)panel.getGraphics();

also be care to not repaint everything : every Graphics object have a clip area associated to it g.getClip(), you must get it to know what area you must repaint (this will be more efficient to only repaint the clip area because everything outer will have no effect and will be discard / not draw by the graphic object => you may have compute & draw the whole Graphics for nothing

@broumbroum: Thanks! It works like a charm now.

@DzzD: You had me until the part about clips. I’m not exactly sure what you mean there. I’ve only really got one Graphics2D object, to the best of my understanding, so why/how would it have multiple clips?

One of the things that has kind of puzzled me is why I am not allowed to declare Graphics objects in the same way I declare normal objects (i.e. Graphics g = new Graphics();).

for example if a window of antoher software go over your frame than a repaint will be launch by the “system” (AWT/Swing) and the frame paint method like paint(Graphics g) (or anyother system called paint method) may be called with a clipped graphics because not the whole graphics have been occluded(in this case the clip area will be a rectangle where the window is over you frame ).

you can cannot create a graphics object cause it is an abstract object : a graphics object have no sense until it is linked to something where it can paint that’s why you cannot instanciate it with “new Graphics” :

often you will ask an object to give you a graphics object (to be able to paint to that object) :

BufferedImage  bi=new BufferedImage(...)
//If I want to paint on this buffered image I can do the following
Graphics gb=bi.getGraphics(); 

//or another example 

Frame f;
//than later in my code when the frame is visible if I want to paint directyly on it
Graphics g=f.getGraphics()

//or you can also create your own graphics to paint you own object in the way you want....
class MyGraphics extends Graphics
{
	//here implements all original Graphics methods
	
	//for example you may do (to paint to the console)
	public void drawString(String str,int x,int y)
	{
		System.out.println(str +" at " + x + "," + y);
	}
	
	//or to paint to a remote computer
	public void drawString(String str,int x,int y)
	{
		network.sendDrawStringOrderToRemoteComputer(str,x,y);
	}
}

EDIT: typos… you cannot create a graphics object cause it is an abstract …

and in shorter :slight_smile: : you should think of Graphics as a tools/way to draw/paint on an object and not as the recipient to receive draw/paint

such clipping area is returned by the getVisibleRect() of JComponent. However, it won’t be usable in an active rendering mode. the clipping area will be useful when using the component in a Swing managed context, e.g. you paint a custom an animated component on a dektop panel.
In that particular case, update(getGrahics()) may be replaced by a call to paintImmediately(getVisiblerect) which will repaint on the visible graphics clipped area. This can save memory when you are displaying several panels.