1

This is a weird problem. I have a solution for it, but I don't know WHY the problem occurs in the first place. Observe the code below:

// VERSION 1

public class test {

    public static void main(String[] args) {
        JFrame mainFrame = new JFrame("Test");
        JPanel inputPanel = new JPanel();

        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.getContentPane().add(BorderLayout.CENTER, inputPanel);
        mainFrame.setBounds(100, 50, 200, 100);
        mainFrame.setVisible(true);

        JButton inputFileButton = new JButton("BROWSE");
        inputPanel.add(inputFileButton);
    }
}

It works as expected. The button does nothing, but it renders correctly. Now, I add a JFileChooser (which I plan to do something with later, but for now all I'm doing is instantiating it).

// VERSION 2

public class test {

    public static void main(String[] args) {
        JFrame mainFrame = new JFrame("Test");
        JPanel inputPanel = new JPanel();

        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.getContentPane().add(BorderLayout.CENTER, inputPanel);
        mainFrame.setBounds(100, 50, 200, 100);
        mainFrame.setVisible(true);

        JFileChooser inputFileChooser = new JFileChooser(); // NEW LINE

        JButton inputFileButton = new JButton("BROWSE");
        inputPanel.add(inputFileButton);
    }
}

All of a sudden my button no longer renders. Why? I know two ways to make it work again, but neither makes 100% sense to me. One way to fix it:

// VERSION 3

public class test {

    public static void main(String[] args) {
        JFrame mainFrame = new JFrame("Test");
        JPanel inputPanel = new JPanel();

        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.getContentPane().add(BorderLayout.CENTER, inputPanel);
        mainFrame.setBounds(100, 50, 200, 100);
        mainFrame.setVisible(true);

        JButton inputFileButton = new JButton("BROWSE");
        inputPanel.add(inputFileButton);

        JFileChooser inputFileChooser = new JFileChooser(); // MOVE LINE TO END
    }
}

So moving that line to the end allows the button to render again, but that still makes no sense to me what an instantiated JFileChooser has to do with the unconnected button. Another way I can fix this issue:

// VERSION 4

public class test {

    public static void main(String[] args) {
        JFrame mainFrame = new JFrame("Test");
        JPanel inputPanel = new JPanel();

        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.getContentPane().add(BorderLayout.CENTER, inputPanel);
        mainFrame.setBounds(100, 50, 200, 100);

        JFileChooser inputFileChooser = new JFileChooser();

        JButton inputFileButton = new JButton("BROWSE");
        inputPanel.add(inputFileButton);

        mainFrame.setVisible(true); // MOVE *THIS* LINE TO THE END            
    }
}

It kind of makes sense why the version above fixes the problem... obviously something about the JFileChoose instantiation was making my button invisible, but this setVisible() method afterwards bring it back into the light. But that still doesn't tell me WHY it went invisible in the first place.

Can somebody please help me figure out what I'm missing? Thanks!

The111
  • 5,757
  • 4
  • 39
  • 55
  • 3
    1) Always create & update the GUI on the EDT. 2) Don't call `setBounds()` or `setSize()`, instead call `pack()`. 3) The order is important. a) Add components b) `pack()` c) `setLocationRelativeTo()` (if needed) d) `setVisible(true)` – Andrew Thompson Apr 07 '12 at 07:39

1 Answers1

5

You are making your mainFrame visible and adding the button afterwards. Take a look at this SO question on what steps you need to take to make sure your button is visible.

The reason why it works in your first example is probably pure luck. Your call to add the button will be performed before the EDT shows your component.

Note: please perform the Swing operations on the EDT

Community
  • 1
  • 1
Robin
  • 36,233
  • 5
  • 47
  • 99
  • Thanks. I am new to the EDT concept, but from some quick research I've done, it sounds like I only need to explicitly reference the EDT if I am in a different thread. Were any of my examples above NOT "performing Swing operations on the EDT?" I understand better now the sequence I should follow, thanks to yours and Andrew's answers, just making sure I'm not overlooking something else about the EDT. – The111 Apr 07 '12 at 07:55
  • 1
    Your main method runs on a different thread, so none of the Swing operations are performed on the EDT. You should use a `SwingUtilities.invokeLater` call in your main method to construct your UI. The must-read tutorial is [this one](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/) – Robin Apr 07 '12 at 07:58