Archive for the 'Java' Category

Skinning a Slider with Nimbus

Wednesday, August 20th, 2008

So time for a example of how to skin a Swing JSlider using the Nimbus Look and Feel and some simple painting code. So this is what we get with the standard Nimbus look slider on a dark grey background.

Slider Default Look

All of the Nimbus skin comes from a set of properties in the UIManager defaults table. The keys we will be changing for this example are:

  • “Slider.thumbWidth”
  • “Slider.thumbHeight”
  • “Slider:SliderThumb.backgroundPainter”
  • “Slider:SliderTrack.backgroundPainter”

You can customize the look for a Component either globally for all instances of the component or locally for a single component instance. To change all sliders globally you can set these properties using UIManager.put(key,value) but in this example I will just set them locally for a single slider. To set UI defaults localy for a single component instance you need to create a UIDefaults map, insert you properties and then set it as a client property on the component:

                JSlider slider = new JSlider(0, 100, 50);
                UIDefaults sliderDefaults = new UIDefaults();
                ....
                sliderDefaults.put(<<key>>,<<value>>)
                ....
                slider.putClientProperty("Nimbus.Overrides",sliderDefaults);
                slider.putClientProperty("Nimbus.Overrides.InheritDefaults",false);

The “Nimbus.Overrides.InheritDefaults” key states if the values in “Nimbus.Overrides” should be merged with the defaults(false) or replace them(true). So next some examples for what properties we should set to skin the slider:

                sliderDefaults.put("Slider.thumbWidth", 20);
                sliderDefaults.put("Slider.thumbHeight", 20);
                sliderDefaults.put("Slider:SliderThumb.backgroundPainter", new Painter() {
                    public void paint(Graphics2D g, JComponent c, int w, int h) {
                        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                        g.setStroke(new BasicStroke(2f));
                        g.setColor(Color.RED);
                        g.fillOval(1, 1, w-3, h-3);
                        g.setColor(Color.WHITE);
                        g.drawOval(1, 1, w-3, h-3);
                    }
                });
                sliderDefaults.put("Slider:SliderTrack.backgroundPainter", new Painter() {
                    public void paint(Graphics2D g, JComponent c, int w, int h) {
                        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                        g.setStroke(new BasicStroke(2f));
                        g.setColor(Color.GRAY);
                        g.fillRoundRect(0, 6, w-1, 8, 8, 8);
                        g.setColor(Color.WHITE);
                        g.drawRoundRect(0, 6, w-1, 8, 8, 8);
                    }
                });

The lets pop that code into a sample app and run it and see what it looks like.

Slider Demo

The original Nimbus slider on the bottom and the skinned one on top, both running in the same application. Here is the source so you can try it your self. Let me know if this was useful and what other examples you would like to see.

Java Icon
SliderSkinDemo.java

A very late “Nimbus is Done” blog!

Wednesday, August 20th, 2008

Wow its been crazy, we have finally finished Nimbus for 6u10 and release candidate is out there Java 6u10 RC Download, have done Java One and I am now knee deep in Java FX. I have about 10 half completed blogs and just never seem to find the time to finish them. As well as being mega busy with Nimbus and Java FX I have just moved back from California to the UK. Moving is always way too time consuming and expensive.

If you missed our talk and BOF at Java One this year here are the presentations:

Java One 2008 Nimbus Talk PDF

Java One 2008 Nimbus BOF Presentation PDF

A lot of you have been asking about the Nimbus Designer Tool that I demoed at Java One. I have been working at getting it opensourced but it is a slow bureaucratic process so I am sorry. In the mean time I thought I would try and do a couple blogs on how you can skin Nimbus your self with out the tool. It is very easy to do providing you are not worried about getting your hands dirty writing some Java 2D drawing code. You could always use images or a SVG library if you don’t fancy raw Java 2D. I would like to split the designer tool into 2 parts the first part the lets you create a Painter classes with Java 2D drawing code by drawing graphics. The second part would let you assign painters to components and generate the code to populate the UIManager defaults table. But both those parts are not hard to do your self if we help you get started so I will see what I can do.

So just a quick hello to say I am still alive, next to try and post a couple blogs on how to skin Nimbus.

SwingSet 3 with Nimbus

Nimbus: Large, Small, Mini Components

Friday, December 7th, 2007

In the original design for Nimbus there were large,small and mini versions of components. Small and mini components are very useful when you are creating tool pallets or other UI where space is very tight. Apple recently added this to their new look and feel in the latest java versions see Technical Note TN2196. We are using the same client property key and values as Apple to be compatible but I have also added “large” as a option. Not sure “large” is as useful as “small” or “mini” but might look good in wizards or dialogs. Check out the screenshot to see how they look. Nimbus Small Mini 600

Faster Swing Lists and Tables up to 88,000x

Tuesday, November 6th, 2007

Swing lists and tables use an implementation of ListSelectionModel to handle keeping track of the selection. Every time you change the selection or rows then the component sends those changes to the selection model to keep it in sync. The default implementation that you get is DefaultListSelectionModel. Its implmentation is highly optimized for certain kinds of operations but has had to make comprimizes for a some other operations.

Back when I was doing Imagery I created an alternative implementation of ListSelectionModel because I needed an easy way to convert the selection into a SQL where clause. After much thought I came up with the idea of representing the selection as a list of ranges of selected ids. This means that you can then convert the selection into a list of "id >= rangeMin AND id <= rangeMax" SQL expressions. This solution is well suited to the case where the selection is created by the user. The only way for a user to create more than one range is to "Control" click the rows. It is unlikely that the user will ever select more than a couple dozen ranges. This results in a model that is always simple however many rows there are in the List/Table. As a by product of this alternative selection model can be up to 88,000x faster than the default with large amounts of rows. I have put together a couple of JUnit tests, one does a huge amount of random operations on both a DefaultListSelectionModel and a RangeListSelectionModel and compares the results at each stage. This means that I can be very sure that my implementation is fully compatible with the default one. The second unit test does some performance tests to compare the two models. The data set is 1,000,000 rows and 20,000 operations for each test

Performance Results

Test Default Model Ranges Model Perfomance Gain
Add selection interval 0.017 s 2.533 s -149x
Is selected index 0.009 s 0.011 s -1.2x
Remove index interval 16:09 min 0.011 s 88,053x
Set selected item 1:30 min 0.067 s 1405x
20k Random Operations 4:25 min 0.055 s 4810x
Average 18,823x

As you can see from the results that it is a large win on average. The test that it is slow at is AddSelectionInterval this is because it ends up with 17482 ranges. This should never happen in most real world applications, the only way I can see it happen is if you select all table rows that meet some search criteria which results in 1000s of random rows being selected. In all cases where the selection is user controlled then this will never happen.

Conclusion

I have seen bug reports coming in of hugely bad JTable performance when adding/removing rows from a huge table. After profiling I found that it was the SelectionModel causing the problems. You can see from the performance results that it can take minutes to do a large chunk of selection changes on a big table. So please try out my Ranges implementation in your application and tell me how it performs. If the responses are good I could change it to the default ListSelectionModel implementation in Java 7. To use it you just need to add the line "myTable.setSelectionModel(new RangeListSelectionModel());".

Code Downloads

Here are the sources so you can try it out for yourself:

Java Icon
RangeListSelectionModel.java
Java Icon
RangeSelectionModelPerformanceTest.java
Java Icon
RangeSelectionModelTest.java

JavaOne 2008 Papers

Tuesday, October 30th, 2007

Its already that time of year again to start writing up all your great ideas for Java One Desktop talks for next year. Its only two and a half weeks till they close for submissions so hurry up. Click here for details for paper submission.

I am planning on submitting a talk on Nimbus and the new Nimbus Designer tool. Covering:

  • Using Nimbus L&F in your applications
  • Designing for cross-platform, how to design your application to look good on all platforms
  • Customizing Nimbus
  • Creating new look and feels using the designer tool based on Nimbus
  • Creating your own components with Nimbus L&F themeing support
  • Designing the look for your own components using the deisgner tool

Might have too much to cover in a hour, don’t want to scare you all off. Any thoughts on what topics you think are the most important/intresting in case I need to cut bits out or anything I didn’t mention here?

JavaOne 2008