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 .
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 .
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...
You can match the system's look and feel like this:
that just gets the system L&F, which would be more original than an external L&F anyways.
hope this helps!