New Java client properties on Mac
August 22, 2009
There are a few new client properties on the Mac, that haven’t yet been documented (though I’ve been assured that they’re safe to use). The great thing about the way Apple has been using client properties on the Mac, is that they make it easy for you to get closer to being a great Mac app, while not breaking your fidelity on other platforms. They’re really great if you want to fit in on your target platform, whereas in Mac Widgets for Java, I’m aiming for always looking like a Mac app.
The screenshots above show the new client properties that give you access to SourceList style selection painters (demo’d in the source code below). Note that these painters accurately pick up whether the user is using Aqua or Graphite — that’s a big bonus.
Here’s a listing of the new client properties:
List.sourceListBackgroundPainter List.sourceListSelectionBackgroundPainter List.sourceListFocusedSelectionBackgroundPainter List.evenRowBackgroundPainter List.oddRowBackgroundPainter
Here’s a little bit of code that puts a few of the new SourceList client properties to work (seen above):
public class NewClientProperties { /** * Create a SourceList style JList. */ private static JList createMacSourceList() { JList list = new SourceList(); // install a custom renderer that wraps the already installed renderer. list.setCellRenderer(new CustomListCellRenderer(list.getCellRenderer())); return list; } /** * A custom JList that renders like a Mac SourceList. */ public static class SourceList extends JList { public SourceList() { // make the component non-opaque so that we can paint the background in // paintComponent. setOpaque(false); } @Override protected void paintComponent(Graphics g) { // paint the background of the component using the special Mac border // painter. Border backgroundPainter = UIManager.getBorder("List.sourceListBackgroundPainter"); backgroundPainter.paintBorder(this, g, 0, 0, getWidth(), getHeight()); super.paintComponent(g); } } /** * A custom ListCellRenderrer that wraps a delegate renderer. */ public static class CustomListCellRenderer extends JPanel implements ListCellRenderer { private ListCellRenderer fDelegate; private boolean fIsSelected; private boolean fIsFocused; public CustomListCellRenderer(ListCellRenderer delegate) { this.setOpaque(false); this.setLayout(new BorderLayout()); this.setBorder(BorderFactory.createEmptyBorder(1,5,1,5)); fDelegate = delegate; } public Component getListCellRendererComponent( JList list, Object value, int index,boolean isSelected, boolean cellHasFocus) { this.removeAll(); // remember the isSelected and cellHasFocus state so that we can use those // values in the paintComponent method. fIsSelected = isSelected; fIsFocused = cellHasFocus; // call the delegate renderer JComponent component = (JComponent) fDelegate.getListCellRendererComponent( list, value, index, isSelected, false); // make the delegate rendere non-opqaue so that the background shows through. component.setOpaque(false); this.add(component, BorderLayout.CENTER); return this; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // if the item was selected, then paint the custom Mac selection background. if (fIsSelected) { Border backgroundPainter = fIsFocused ? UIManager.getBorder("List.sourceListFocusedSelectionBackgroundPainter") : UIManager.getBorder("List.sourceListSelectionBackgroundPainter"); backgroundPainter.paintBorder(this, g, 0, 0, getWidth(), getHeight()); } } } public static void main(String[] args) { JList list = createMacSourceList(); list.setListData(new String[]{ "BMW", "Chevy", "Dodge", "Infiniti", "Nissan", "Porsche"}); JScrollPane scrollPane = new JScrollPane(list); scrollPane.setBorder(BorderFactory.createEmptyBorder()); JFrame frame = new JFrame(); frame.add(scrollPane); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(200,200); frame.setLocationRelativeTo(null); frame.setVisible(true); } }
August 22, 2009 at 12:55 am
Ken,
Would this work with a JTree as well? Also, I imagine (but am too lazy^H^H^H^H busy at the moment to test for myself) that you’d get a NullPointerException in SourceList#paintComponent on another OS where these client properties are not defined, right?
Thanks,
Jamie
August 22, 2009 at 1:02 am
Hi Jamison,
This would work in any component. You’d need to protect from null on other platforms — in fact, I wouldn’t’ even try to do the painting on other platforms.
-Ken
August 24, 2009 at 11:50 am
How can I apply this to JTrees? I’ve changed the ListCellRenderer to TreeCellRenderer, but only the first “cell” of JTrees (that one with the icons) is rendered. The other cell containing the value/text is not rendered in the sourclist-style…
August 24, 2009 at 1:25 pm
Hi Daniel,
Applying this to a JTree will be a bit trickier. Try following my instructions here, which will show you how to make JTree fill it’s width. Also, you can look at SourceListTreeUI to see how I install renderers to create the SourceList effect.
-Ken
August 22, 2009 at 8:22 am
neat! I gotta check this out. thanks for posting.
August 22, 2009 at 5:14 pm
Hendrik,
Does beaTunes use MacWidgets ?
Thanks,
August 24, 2009 at 9:54 am
Yes, It does, but so far only for scrollbars. I’d like to switch other ui elements over to macwidgets when I have the time..
August 23, 2009 at 9:25 pm
[…] Orr has a post up detailing some new Java client properties available on Mac platforms. These properties mean that components can get ever-closer to looking like proper Mac […]
August 24, 2009 at 9:50 am
do you have included this feature already in the latest dev-build?
August 24, 2009 at 10:42 am
Hi Daniel,
I’m not currently using these client properties in Mac Widgets for Java. I may cut over to them though, so that on the Mac the user’s choice of Aqua or Graphite is picked up.
-Ken
February 18, 2011 at 3:45 pm
[…] des barre de header à la iTunes , faire des listes au look Apple bref que du […]
August 6, 2014 at 4:14 am
Do we have a list of these somewhere? I just discovered this one in particular in the source code and am amazed that it wasn’t documented in the same doc as all the other custom component styles.