1

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();
    }    
}
4

1 回答 1

3

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...

  • You shouldn't be throwing away your exceptions. At the very least, you should be printing the exception or logging it.
  • You should be using an 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...
  • Even though you are setting the size of the parent frame, your 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.
  • You may wish to take a look at Initial Threads and the important of using EventQueue.invokeLater to launch your UI
  • System.getProperty( "user.dir" )+"/src/"+filename) looks like it should be referencing an embedded resource...
于 2013-09-19T01:10:58.613 回答