Robin92
Robin92

Reputation: 561

Strange issue with components

I'm developing an application on my Java classes and hit a wall with a strange issue. I need to represent data in a grid, so using GridLayout is an obvious choice, but here's a problem. I keep on getting almost empty frame (notice tiny white rectangle in top left corner).

issue

Here's a code snippet producing this result

//not important class code 
public static void main(String args[]) {    
    JFrame frame = new JFrame("Wolves & Rabbits");
    frame.setSize(640, 480);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //want to create a 12x9 grid with 2 black and 4 pink rectangles
    Board board = new Board(12, 9, 2, 4, 1000);

    frame.add(board);

    frame.setResizable(false);
    frame.setVisible(true);
}

//Board.java (Board class) extends JPanel
public JPanel fields[][];
private Integer boardWidth, boardHeight;
private ArrayList<AnimalThread> animals;
private Integer wolvesCount, rabbitsCount;

public Board(int w, int h) {
    super(new GridLayout(h, w, 4, 4));

    fields = new JPanel[w][h];
    boardWidth = new Integer(w);
    boardHeight = new Integer(h);
    animals = null;
    wolvesCount = new Integer(0);
    rabbitsCount = new Integer(0);

    //creating white rectangles
    for (int i = 0; i < boardHeight; i++)
        for (int j = 0; j < boardWidth; j++) {
            fields[j][i] = new JPanel(true);
            fields[j][i].setBackground(AnimalThread.NONE);
            this.add(fields[j][i]);
        }

    AnimalThread.setLinkToBoard(this);
}

public Board(int w, int h, int wolves, int rabbits, int k) {
    this(w, h);

    animals = new ArrayList<AnimalThread>();

    while (boardWidth*boardHeight < 2*wolves*rabbits) {
        wolves--;
        rabbits--;
    }       
    wolvesCount = wolves;
    rabbitsCount = rabbits;

    WolfThread.setRabbitsCount(rabbitsCount);

    //randomly place colored rectangles
    this.randomize(wolves, rabbits, k);     
}

The strange thing is that not changing Board class at all and with a little change in main method I was able to display the proper grid.

issue resolved

In this case the main method is

//not important class code
public static void main(String args[]) {    
    JFrame frame = new JFrame("Wolves & Rabbits");
    frame.setSize(640, 480);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    Board board = new Board(12, 9, 2, 4, 1000);

    //THE CHANGE!
    JPanel panel = new JPanel(new GridLayout(12, 9, 4, 4));
    for (int i = 0; i < 9; i++)
        for (int j = 0; j < 12; j++) {
            JPanel tmp = board.fields[j][i];
            panel.add(tmp);
        }
    frame.add(panel);

    frame.setResizable(false);
    frame.setVisible(true);
}

Anyone has idea of what's causing this irritating issue? Any clue would be appreciated.

Upvotes: 1

Views: 84

Answers (1)

Jasper Siepkes
Jasper Siepkes

Reputation: 1405

When you are working with Swing you must execute the Swing UI code on the EDT. So at the very least your main method should look like this:

public static void main(String args[]) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            JFrame frame = new JFrame("Wolves & Rabbits");
            frame.setSize(640, 480);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            // want to create a 12x9 grid with 2 black and 4 pink rectangles
            Board board = new Board(12, 9, 2, 4, 1000);

            frame.add(board);

            frame.setResizable(false);
            frame.setVisible(true);
        }
    });
}

Accessing variables which are Swing objects from an other thread then the EDT will cause problems. Many of these problems will be intermittent and hard to trace (like most concurrency problems).

The name of the 'AnimalThread' object seems to imply its a Thread. You can't (well actually you can as you demonstrated :-) directly Swing objects which 'live' on the EDT. If another Thread wants to change something on the EDT it needs to use the 'SwingUtilities.invokeLater' or 'SwingUtilities.invokeAndWait' method.

Upvotes: 1

Related Questions