views:

269

answers:

2

The two examples shown below are same. Both are supposed to produce same result e.g. generate the coordinates of images displayed on JPanel. Example 1, works perfectly (print the coordinates of images), however example 2 returning 0 for the coordinate.

I was wondering why because, I have put the setvisible (true) after adding the panel, in both examples. The only difference is that example 1 used extends JPanel and example 2 extends JFrame

EXAMPLE 1:

    public class Grid extends JPanel{
       public static void main(String[] args){
          JFrame jf=new JFrame();
          jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);      
          final Grid grid = new Grid();
          jf.add(grid);
          jf.pack();

          Component[] components = grid.getComponents();        
          for (Component component : components) {
           System.out.println("Coordinate: "+ component.getBounds());       
          }   

          jf.setVisible(true);        
        }
    }

EXAMPLE 2:

public class Grid extends JFrame {

  public Grid () {
    setLayout(new GridBagLayout());
    GridBagLayout m = new GridBagLayout();
    Container c = getContentPane();
    c.setLayout (m);
    GridBagConstraints con = new GridBagConstraints();

    //construct the JPanel
    pDraw = new JPanel();
    ...
    m.setConstraints(pDraw, con);
    pDraw.add (new GetCoordinate ()); // call new class to generate the coordinate
    c.add(pDraw);

    pack();
    setVisible(true);
    }

    public static void main(String[] args) {
       new Grid();
    }
   }
A: 

A common cause of such anomalies is failing to start on the EDT. In this case, I can't tell from your code what is different: in particular, it's not clear where the second example prints.

trashgod
It appears that both of these code snippets make this mistake - I don't see `SwingUtilities.invokeLater()` or `SwingUtilities.invokeAndWait()` anywhere here.
Joe Carnahan
+1  A: 

The problem is that in the second example, you are trying to print out the bounds of a component before the component has been added to its container (by calling add()) and before the frame's contents have been laid out (by calling pack()).

Here is my attempt to reproduce Example 1. ...

Here is my attempt to reproduce Example 2. I added the SwingUtilities call to put things in the right thread, and I filled in the contents of the GetCoordiates constructor with help from your comments:

class GetCoordinate extends JLabel {
    public GetCoordinate() {
        setText("Foo!");
        System.out.println("Coordinate: " + this.getBounds());
    }
}

public class Grid extends JFrame {
    public Grid() {
        setLayout(new GridBagLayout());
        GridBagLayout m = new GridBagLayout();
        Container c = getContentPane();
        c.setLayout(m);
        GridBagConstraints con = new GridBagConstraints();

        // construct the JPanel
        final JPanel pDraw = new JPanel();
        m.setConstraints(pDraw, con);
        pDraw.add(new GetCoordinate()); // call new class to generate the
                                        // coordinate
        c.add(pDraw);

        pack();
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Grid();
            }
        });
    }
}

Just as you described, it prints out a size of zero:

Coordinate: java.awt.Rectangle[x=0,y=0,width=0,height=0]

However, if you print out the size after the component has been added and the frame has been packed, it should work. Here is a modified version of my Example 2, where I added a method GetCoordinate.printBounds() and call that method everything has been added and laid out:

class GetCoordinate extends JLabel {
    public GetCoordinate() {
        setText("Foo!");
        // Let's not try to do this here anymore...
//        System.out.println("Coordinate: " + this.getBounds());
    }

    public void printBounds() // <-- Added this method
    {
        System.out.println("Coordinate: " + this.getBounds());
    }
}

public class Grid extends JFrame {
    public Grid() {
        setLayout(new GridBagLayout());
        GridBagLayout m = new GridBagLayout();
        Container c = getContentPane();
        c.setLayout(m);
        GridBagConstraints con = new GridBagConstraints();

        // construct the JPanel
        final JPanel pDraw = new JPanel();
        m.setConstraints(pDraw, con);
        final GetCoordinate content = new GetCoordinate();
        pDraw.add(content);
        c.add(pDraw);

        pack();
        setVisible(true);
        content.printBounds();  // <-- Added this
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Grid();
            }
        });
    }
}

With these changes, I get the following console output, including a nonzero size for my content:

Coordinate: java.awt.Rectangle[x=5,y=5,width=23,height=16]

Joe Carnahan
I have tried to change it, but it seems doesn't make any difference. In the second example if I put the pack() before the pDraw.add (new GetCoordinate ()), the JPanel doesn't show up :-(
Jessy
I'm trying to reproduce your problem on my system. What happens in the `GetCoordinate` constructor? If you are trying to print out the bounds of the `GetCoordinate` object (or the `pDraw` object) inside the constructor, that's not going to work because the `GetCoordinate` object isn't added to `pDraw` until *after* the constructor finishes executing.
Joe Carnahan
Thanks for you help. Yes, the printing of the coordinate was in the constructor of GetCoordinate, and it give me this component.getBounds()java.awt.Rectangle[x=0,y=0,width=0,height=0]
Jessy
Yeah, printing the coordinate inside the constructor won't work, unfortunately - The component's constructor needs to complete *and* the component needs to be added *and* the frame needs to be packed for the component to know what its size is, and none of those things have happened yet if you're still inside the constructor. I'll edit my answer to suggest an alternative. :-)
Joe Carnahan
THANK YOU for helping me. I have played around of my code based on your suggestion and it works. Thanks you very much for your kindness.
Jessy