2

I'm trying to make a combo box in Swing (under Java 7) look like a native combo box. It turns out that a JPopupMenu is used to display the options of the combo box, so it turns into a matter of making a JPopupMenu look native enough.

If I use the default Aqua look and feel, I get square edges, which is not right at all, so we'll throw that idea away right off the bat. So of course, one turns to Quaqua, which is supposed to fix this sort of thing.

public class PopupMenuTest implements Runnable {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new PopupMenuTest());
    }

    @Override
    public void run() {
        try {
            UIManager.setLookAndFeel(QuaquaManager.getLookAndFeel());
            // Uncomment this for the second example
            //PopupFactory.setSharedInstance(new CustomisedScreenPopupFactory());
        } catch (Exception ignore) {}

        JComboBox<String> comboBox = new JComboBox<>();
        comboBox.setModel(new DefaultComboBoxModel<>(
            new String[] { "One", "Two", "Three" }));

        JFrame frame = new JFrame("Test");
        frame.setLayout(new FlowLayout());
        frame.add(comboBox);
        frame.setSize(300, 200);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

This gives me a popup menu which does have rounded corners but has filled in the corners with black.

Where the code is commented out above, I tried jamming in a custom screen popup factory.

public class CustomisedScreenPopupFactory extends PopupFactory {
    private final PopupFactory delegate;

    public CustomisedScreenPopupFactory() {
        PopupFactory delegate;
        try {
            Class<? extends PopupFactory> clazz =
                Class.forName("com.apple.laf.ScreenPopupFactory")
                    .asSubclass(PopupFactory.class);
            Constructor<? extends PopupFactory> constructor =
                clazz.getDeclaredConstructor();
            constructor.setAccessible(true); // hacks
            delegate = constructor.newInstance();
        } catch (Exception ignore) {
            delegate = new PopupFactory(); // has to be set to something
        }
        this.delegate = delegate;
    }

    @Override
    public Popup getPopup(Component owner, Component contents, int x, int y) {
        Popup popup = delegate.getPopup(owner, contents, x, y);

        try {
            Method method = Popup.class.getDeclaredMethod("getComponent");
            method.setAccessible(true);
            Component component = (Component) method.invoke(popup);
            if (component instanceof JWindow) {    // always is, so far
                JWindow window = (JWindow) component;
                JRootPane rootPane = window.getRootPane();

                // This call here is what all the rest of the boilerplate was
                // added in order to access.
                AWTUtilities.setWindowOpaque(window, false);
            }
        } catch (Exception e) {
            Logger.getLogger(getClass()).error("Couldn't customise the popup window", e);
        }

        return popup;
    }
}

This gives me an interesting result where the black corners are gone, but so is the shadow.

Problem is, I want both the rounded corners and the shadow. Is it possible to get both?

Incidentally, I notice that IDEA does get it right, but I couldn't figure out from their source why it would work, so I wonder if it's because it's running on Java 6 and not Java 7...

Hakanai
  • 12,010
  • 10
  • 62
  • 132
  • The Quaqua look and feel is from pre 10.5?? Based on the gumdrop-blue color of the combo box it's going to look really out of place on anything that actually runs Java 7. If you want to get an effect that looks similar to the native look and feel for a combobox, stick to the system look and feel, but make it editable. This looks far more like the native one. – Anya Shenanigans Feb 04 '14 at 17:33
  • I found the popup on the native one to lack the rounded corners. And making it editable makes it pop downwards, which is even more incorrect for a combo box which is supposed to be for selecting an option. Pop-downs are usually for the case where you're selecting an action to perform, which is subtly different. Since posting this I have started a project called Haqua to implement hacky workarounds for all of this stuff. – Hakanai Feb 05 '14 at 04:20
  • My bad, I was mixing up a Popup Button and a ComboBox. They're completely different things. – Anya Shenanigans Feb 05 '14 at 11:27

1 Answers1

-1

You can match the system's look and feel like this:

    try{
    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName);
    catch(Exception e){}

that just gets the system L&F, which would be more original than an external L&F anyways.

hope this helps!