3

I ran into a strange kind of behavior when putting JComboBox components inside a GroupLayout. I've reduced the code to the below minimal example, featuring exactly one JComboBox layed out by GroupLayout.

The observed behavior is as follows:

  • When the frame is smaller than the expanded combo box list (with dummy entries a, b, c), clicking on the little down arrow on the combo box opens it correctly.
  • When I resize the frame to be bigger than the expanded combo box list would be, the expanded combo box list is not opened!

What I've found out already:

  • When the parent window of a JComboBox is too small, javax.swing.PopupFactory creates a HEAVY_WEIGHT_POPUP component.
  • When the parent window is big enough, a LIGHT_WEIGHT_POPUP is being created.
  • The behavior is definitely related to GroupLayout or some side effects of it, since any other layout managers I tried work just fine.
  • When using addGap() in GroupLayout the problem changes a bit, i.e. the window sizes where the JComboBox does not show up change.

This is the sample code - comments are welcome:

import java.awt.BorderLayout;

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JRootPane;

public class DummyUI_cbdiagnosis extends javax.swing.JPanel {
    private javax.swing.JComboBox cbCategory;

    public DummyUI_cbdiagnosis() {
        initComponents();
    }

    private void initComponents() {
        cbCategory = new JComboBox();
        cbCategory.setModel(new javax.swing.DefaultComboBoxModel(new String[] {
                "a", "b", "c" }));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(layout.createParallelGroup(
                javax.swing.GroupLayout.Alignment.LEADING).addGroup(
                layout.createSequentialGroup().addComponent(cbCategory,
                        javax.swing.GroupLayout.PREFERRED_SIZE,
                        javax.swing.GroupLayout.PREFERRED_SIZE,
                        javax.swing.GroupLayout.PREFERRED_SIZE)));
        layout.setVerticalGroup(layout.createParallelGroup(
                javax.swing.GroupLayout.Alignment.LEADING).addGroup(
                layout.createSequentialGroup().addComponent(cbCategory)
        ));
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JRootPane rootPane = frame.getRootPane();
        rootPane.setLayout(new BorderLayout());

        DummyUI_cbdiagnosis panel = new DummyUI_cbdiagnosis();
        rootPane.add(panel, BorderLayout.NORTH);

        frame.pack();
        frame.setVisible(true);
    }
}
Roman C
  • 49,761
  • 33
  • 66
  • 176

1 Answers1

6

Never ever add components to the RootPane itself, rather add them to the contentPane.

frame.add(panel);

or

frame.setContentPane(panel);

A RootPane has control of where to put the:

  • Menu bar.
  • Content.
  • Glass pane.
  • And most important, lightweight popups (inc. JComboBox), dialogs, drag and drops, etc.

RootPane uses a special layout manager called RootLayout, and shouldn't be changed to BorderLayout.

Mordechai
  • 15,437
  • 2
  • 41
  • 82
  • Would you explain why I cannot add to the root pane? – Roman C Nov 16 '12 at 17:11
  • Not your down-voter, but `frame.add()` _forwards_ to the content pane, making `getContentPane()` superfluous; `frame.setContentPane()` _replaces_ the content pane, perhaps unintentionally. More [here](http://stackoverflow.com/a/11769153/230513). – trashgod Nov 16 '12 at 20:22
  • @trashgod seems I was backdated, `JFrame#add(...)` used to throw an `Error` on older versions of JDK. – Mordechai Nov 16 '12 at 20:32
  • Thanks, I did not realize that there is getRootPane() *and* getContentPane() - I mistook getRootPane() for the method that gives you the frame's top level pane (did remember though that frame.add() wasn't working in old JDKs; funny thing). – user1830252 Nov 18 '12 at 21:22