I am making a program that takes a two dimensional integer array and uses its data to draw tiles to the screen in the arrangement specified in the array. Without modifying any of the code, the program will execute fine about 4 out of 5 times. Other times the custom JPanel will not display anything. After inserting system.out.print() in various places I have determined that it is caused by the paintComponent method not being called when nothing is displayed. Obviously it is called when the tiles are displayed perfectly. I can't seem to find the source of this inconsistency. Why would it work the majority of the time and not every once in a while?
Its called Isopanel because it will eventually display tiles in an isometric formation. 0s equate to water tiles and 1s equate to sand tiles.
JPanel Class
public class IsoPanel extends JPanel
{
private ArrayList <BufferedImage> tiles;
private int[][] leveldata =
{
{0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0}
};
public IsoPanel()
{
tiles = new ArrayList<BufferedImage>();
tiles.add(Frame.loadImage("water.png"));
tiles.add(Frame.loadImage("sand.png"));
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
for (int i=0; i<10; i++)
{
for (int j=0; j<10; j++)
{
int x = j * 50;
int y = i * 50;
int tileType = leveldata[i][j];
placeTile(tileType, x, y, g);
}
}
}
public void placeTile (int tile,int x,int y, Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
g2.drawImage(tiles.get(tile), null, x, y);
}
}
and JFrame class:
public class Frame extends JFrame
{
public Frame()
{
super ("Iso");
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds(0,0,screenSize.width, screenSize.height);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setVisible(true);
BorderLayout bord = new BorderLayout();
setLayout(bord);
IsoPanel iso = new IsoPanel();
add(iso,BorderLayout.CENTER);
GridLayout grid = new GridLayout(1,1);
iso.setLayout(grid);
iso.setVisible(true);
}
public static BufferedImage loadImage(String filename)
{
{
try
{
return ImageIO.read(new File(System.getProperty( "user.dir" )+"/src/"+filename));
}
catch(IOException e)
{
}
}
return null;
}
public static void main(String[] args)
{
Frame one = new Frame();
}
}
The main issue is the fact that you are calling setVisible
on your frame before you've finished initialising the child components. This is a known issue with how frame prepares it's state...
So, instead of...
public Frame()
{
/*...*/
setVisible(true);
/*...*/
add(iso,BorderLayout.CENTER);
}
Try...
public Frame()
{
/*...*/
add(iso,BorderLayout.CENTER);
/*...*/
setVisible(true);
}
Additional...
ImageObsever
when drawing images. Instead of g2.drawImage(tiles.get(tile), null, x, y);
, you should try using g2.drawImage(tiles.get(tile), x, y, this);
. Images aren't always in state to be rendered immediately, this provides a means for the component to react to changes in the image state and automatically repaint themselves...IsoPanel
component should be providing layout hints in the form of overriding getPreferredSize
, allowing you to simply pack
the main window. This discounts the possibility of different frame border sizes on different platforms and look and feel settings.EventQueue.invokeLater
to launch your UISystem.getProperty( "user.dir" )+"/src/"+filename)
looks like it should be referencing an embedded resource...