I am the lead developer at 'Java Swing Compoments' and am extremely passionate about developing UIs. To this day I still blame Logo the turtle for introducing me to programming... I have never looked back! Rhiannon has posted 6 posts at DZone. View Full User Profile

Java Swing Components Accordion Skinning Tutorial

09.13.2010
| 24337 views |
  • submit to reddit

Before we can begin skinning a JSCAccordion, we need to first decide on what look we want to achieve. After much searching I came across an attractive asp.net accordion which I though would make the perfect subject for this skinning tutorial. This tutorial will show you how to take the the default accordion and skin it to look like the asp.net accordion.

 

Comparing the asp.net accordion to the standard JSCAccordion, one would imagine that it would take a lot of code to perform the transformation, however this is really not the case.

There are a number of options available to us when going about skinning a JSCAccordion, some include extending the existing JSCAccordion, extending an existing AccordionUI, or lastly simply adjusting an accordion's settings in code. I will follow the last approach as I feel this will lead to a simpler demo, but all options are valid.

 

Step 1: Create an instance of JSCAccordion

The first step in our tutorial involves creating a new JSCAccordion and adding the required 'Mail', 'Notes' and 'Contacts' tabs.

JSCAccordion accordion = new JSCAccordion();
		
accordion.addTab("Mail", new JLabel());
accordion.addTab("Notes", new JLabel());
accordion.addTab("Contacts", new JLabel());

 

Although it is possible to add any component to an accordion's tab, we will add a JLabel as they are naturally transparent (non opaque) and will allow us to easily see the tab's background.

Step 2: Adjust basic settings on the JSCAccordion

In order for us to achieve the layout of the asp.net accordion, we will need to change a few basic settings on the JSCAccordion.

  • We need to change the orientation of the accordion to render vertically.

  • The tab height must be set to 31 pixels.

  • We need to disable the rendering of the accordion's shadows.

  • The asp.net accordion has a border comprising a black then white rectangle.

    //lays out the accordion's tabs to move vertically.
    accordion.setTabOrientation(TabOrientation.VERTICAL);
    //adjusts the height of the tabs to be 31 pixels
    accordion.setTabHeight(31);
    //stops the accordion rendering its shadows
    accordion.setDrawShadow(false);
    //the asp.net accordion is framed with a black then white border
    accordion.setBorder(BorderFactory.createCompoundBorder(
    	BorderFactory.createLineBorder(Color.BLACK),
    	BorderFactory.createLineBorder(Color.WHITE))
    );


Step 3: Adjusting settings on the SteelAccordionUI

In the previous step, we adjusted settings found on the JSCAccordion, however in order to achieve our final look we will need to adjust some settings on the Accordion's UI. The default UI for the Accordion is the SteelAccordionUI, and it is this UI that we will now manipulate.

In order to bring us one step closer to the asp.net accordion we will now set all the paddings on the SteelAccordionUI to zero.



//we know the default UI for the accordion is the SteelAccordionUI
//so we cast the UI to a SteelAccordionUI.
SteelAccordionUI steelAccordionUI = (SteelAccordionUI) accordion.getUI();
		
//we set all the paddings to zero
steelAccordionUI.setHorizontalBackgroundPadding(0);
steelAccordionUI.setVerticalBackgroundPadding(0);
steelAccordionUI.setHorizontalTabPadding(0);
steelAccordionUI.setVerticalTabPadding(0);
steelAccordionUI.setTabPadding(0)

Setting all the paddings to zero yields us the following result.



Step 4: Replace the background painter

All components from Java Swing Components make use of painters to achieve their look and feel. A painter is a simple class that contains logic to paint (draw) a component. The advantage of keeping this logic in a painter is two fold, firstly its easy to write new painters and secondly all painters are interchangeable. The net result of this is that it becomes very easy to change how a component looks.

The framework upon which all components from Java Swing Components relies includes some simple pre-optimized painters. Instead of creating a new painter from scratch, I will simply make use of existing painters.

Having a look at the asp.net accordion, we can see that we need to draw a gradient from white to grey horizontally to form the background. In order to achieve this we will make use of the GradientColorPainter. This painter paints a simple gradient starting with the startColor and ending with the endColor in a specified direction.

//we will replace the current background painter with a new //GradientColorPainter. 
GradientColorPainter backgroundPainter = new GradientColorPainter();
//paint gradient horizontally
backgroundPainter.setGradientDirection(GradientDirection.HORIZONTAL);
//start with white
backgroundPainter.setStartColor(new Color(255,255,255));
//end with grey
backgroundPainter.setEndColor(new Color(214,213,228));
//apply the painter to the accordion
accordion.setBackgroundPainter(backgroundPainter); 

The result of applying the new background painter renders the following result.

 

 

Step 5: Create a new AccordionTabRenderer

The last step in our skinning process it to code an entirely new AccordionTabRenderer. An AccordionTabRenderer is an interface used by the accordion to 'rubber stamp' a single component for each of the tabs. It works exactly the same as TableCellRenderers on the standard Jtable.

The AccordionTabRenderer interface has a single method getTabComponent.

public JComponent getTabComponent(GetTabComponentParameter parameters); 

The JComponent returned by this method will be used to draw the accordion's tabs. It is the responsibility of the AccordionTabRenderer to read the information from the parameters argument and return an appropriately configured component. The advantage of using a renderer is that it saves memory by only making use of a single component for all the tabs and also allows the developer to return any component they want. The only thing to remember is that the component returned is painted on the screen, and is not added to the accordion as a normal component. For all intensive purposes it is being used as a rubber stamp.

The easiest component to return for this tutorial would be a label, as it has text and an image, which is exactly what we need. We will create a class called a DemoAccordionTabRenderer that implements AccordionTabRenderer and extends JLabel. Whenever the getTabComponent method is invoked, it will return itself.

In the constructor of our class we will load the three images required by the renderer. These images are retrieved in the constructor and not during the getTabComponent method as this would result in io every time a tab is drawn. Unfortunately I did not have access to the icons used in the asp.net accordion so I will be making use of some great icons from the Tango icon library instead.

private ImageIcon mailImage;
private ImageIcon notesImage;
private ImageIcon contactsImage;
	
public DemoAccordionTabRenderer() {
 try {
 //images are loaded in the constructor to improve performance.
 //loading images in the getTabComponent method will result in the images
 //being loaded every time a tab is drawn. 
 mailImage = new ImageIcon(ImageIO.read(Thread.currentThread()
			.getContextClassLoader().getResourceAsStream("mail.png")));
 notesImage = new ImageIcon(ImageIO.read(Thread.currentThread().
			getContextClassLoader().getResourceAsStream("notes.png")));
 contactsImage = new ImageIcon(ImageIO.read(Thread.currentThread().
			getContextClassLoader().getResourceAsStream("contacts.png")));
 } catch (IOException e) {
	e.printStackTrace();
 }
}

Now for the most important method, the getTabComponent method. In this method we will read the information from the parameters argument and setup our renderer.

@Override
public JComponent getTabComponent(GetTabComponentParameter parameters) {
	//read the tabText from the parameter
	setText(parameters.tabText);
	//set the text color to white
	setForeground(Color.WHITE);
	//use a slightly smaller bold font
	setFont(getFont().deriveFont(Font.BOLD, 11f));
	//create a border to help align the label
	setBorder(BorderFactory.createEmptyBorder(0,8,0,0));
	//set the gap between the icon and the text to 8 pixels
	setIconTextGap(8);
		
	//set the appropriate image based on the tabText.
	if ("Mail".equals(parameters.tabText)) {
		setIcon(mailImage);
	}
	if ("Notes".equals(parameters.tabText)) {
		setIcon(notesImage);
	}
	if ("Contacts".equals(parameters.tabText)) {
		setIcon(contactsImage);
	}
		
	//returns itself, which extends JLabel
	return this;
}

 

The final step required to achieve the look of the asp.net accordion is to draw the appropriate background for the AccordionTabRenderer. There are a number of ways this can be achieved, the easiest being to simply override the paintComponent method of the AccordionTabRenderer.

The background of the asp.net accordion's tabs is complex linear gradient comprising of a number of colours. In order to achieve the same look, I will be making use of the LinearGradientColorPainter from the Java Swing Components framework. This painter paints a number of gradients together based on a supplied array of colours and floats. The workings of the painter is beyond the scope of this tutorial, however additional information can be found in the Sun (Oracle) api javadocs of LinearGradientPaint.

In the paintComponent method, we will paint the tab's background using our LinearGradientColorPainter and then simply call super.paintComponent() to paint the standard JLabel on top of the background.

private LinearGradientColorPainter painter = new LinearGradientColorPainter();
	
@Override
protected void paintComponent(Graphics g) {
  //setup the painter fractions
  painter.setColorFractions(new float[]{
		0.0f, 0.49f, 0.5f, 0.51f, 0.8f,	1.0f});

  //setup the painter colors
  painter.setColors(new Color[]{
		new Color(167,163,189),new Color(143,138,169),
		new Color(131,126,160),new Color(116,110,146),
		new Color(119,113,148), new Color(138,133,164)});

  //paint the background
  painter.paint((Graphics2D) g, new Rectangle(0, 0, getWidth(), getHeight()));
		
  //original color on g is stored and then later reset
  //this is to prevent clobbering of the Graphics object.
  Color originalColor = g.getColor();
		
  //paints a simple line on the bottom of the tab
  g.setColor(new Color(87,86,111));
  g.drawLine(0, getHeight()-1, getWidth(), getHeight()-1);
		
  g.setColor(originalColor);

  //draws the label on top of the background we just painted.
  super.paintComponent(g);			
}

The last step is to assign our custom AccordionTabRenderer to the accordion.

//apply the new TabRenderer to the accordion.
accordion.setVerticalAccordionTabRenderer(new DemoAccordionTabRenderer()); 

 

The final result of all our hard work can be seen in the image below.

Although it may have felt like a lot of code, seeing all the code together really shows how easy the skinning process is.

JSCAccordion accordion = new JSCAccordion();
		
accordion.addTab("Mail", new JLabel());
accordion.addTab("Notes", new JLabel());
accordion.addTab("Contacts", new JLabel());

//lays out the accordion's tabs to move vertically.
accordion.setTabOrientation(TabOrientation.VERTICAL);
//adjusts the height of the tabs to be 31 pixels
accordion.setTabHeight(31);
//stops the accordion rendering its shadows
accordion.setDrawShadow(false);
//the asp.net accordion has a border comprising a black then white border
accordion.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.BLACK),BorderFactory.createLineBorder(Color.WHITE)));
		
//we know the default UI for the accordion is the SteelAccordionUI
SteelAccordionUI steelAccordionUI = (SteelAccordionUI) accordion.getUI();	
//we set all the paddings to zero
steelAccordionUI.setHorizontalBackgroundPadding(0);
steelAccordionUI.setVerticalBackgroundPadding(0);
steelAccordionUI.setHorizontalTabPadding(0);
steelAccordionUI.setVerticalTabPadding(0);
steelAccordionUI.setTabPadding(0);
		
//we will replace the current background painter with a new //GradientColorPainter. 
GradientColorPainter backgroundPainter = new GradientColorPainter();
//paint gradient horizontally
backgroundPainter.setGradientDirection(GradientDirection.HORIZONTAL);
//start with white
backgroundPainter.setStartColor(new Color(255,255,255));
//end with grey
backgroundPainter.setEndColor(new Color(214,213,228));
//apply the painter to the accordion
accordion.setBackgroundPainter(backgroundPainter);
	
//apply the new TabRenderer to the accordion.
accordion.setVerticalAccordionTabRenderer(new DemoAccordionTabRenderer());

 

This brings us to the end of the tutorial, for those of you who are made it this far, the final demo jar and source code have been attached to this article. Enjoy

Legacy
Published at DZone with permission of its author, Rhiannon Liebowitz.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Rhiannon Liebowitz replied on Mon, 2010/09/13 - 2:56am

Additional information regarding the accordion can be found here. http://www.javaswingcomponents.com/product/accordion

Manuel Jordan replied on Mon, 2010/09/13 - 11:41am in response to: Rhiannon Liebowitz

Thanks for the link, tell me, can you give us a book recommendation about Swing? Thanks

Rhiannon Liebowitz replied on Mon, 2010/09/13 - 12:02pm in response to: Manuel Jordan

Sure, but it depends what you plan on doing with Swing.

I'm sure there are many good swing books out there, however I can only mention the ones I have been exposed to.

A good general Swing development book would be 'Swing, Second Edition'.

Custom component development would be 'Filthy Rich Clients'.

The sun/oracle swing trails are all really good, with some great examples. 

And I would throw in 'Effective Java' just because it is awesome (although not swing related)!

Jeanette Winzenburg replied on Tue, 2010/09/14 - 3:10am

personally, I would consider an API which forces me into talking to the ui-delegate ... ehem ... a bit incomplete. Nice component, though :-)

CU Jeanette

Rhiannon Liebowitz replied on Tue, 2010/09/14 - 5:24am in response to: Jeanette Winzenburg

Hi Jeanette You are correct in your observation, accessing the ui delegate to change properties is not ideal. I would normally write a new UI delegate rather than tweak an existing UI delegate as the tutorial does. I only chose to do it this way to keep the tutorial simple and side step the additional overhead of explaining how to create and set UI delegates. Also each component receives its own instanceof of UI delegate rather than sharing a single instance, this means its possible to tweak the settings on a particular ui-delegate from a component without affecting all other components. Rhi

Greg Brown replied on Tue, 2010/09/14 - 8:47am

Hi Rhiannon,

Very thorough and interesting piece.

Just for the sake of comparison, here's how you can do something similar using Apache Pivot (which, if you are not familiar with it, is an alternative to Swing for building Java GUIs):

http://ixnay.biz/accordion/accordion.html

The Pivot version can be implemented using only a small amount of markup - no code is necessary (for this example, anyway). Pivot's Accordion doesn't currently support stopped gradient header backgrounds, but this is something we are very likely to add for Pivot 2.0.

Hope you find it useful.

Greg

Manuel Jordan replied on Tue, 2010/09/14 - 10:34am in response to: Rhiannon Liebowitz

Hello Rhiannon, thanks for the book suggestions

About >>Sure, but it depends what you plan on doing with Swing

More interesting about dynamic work with tables together with data models and see a book that uses MVC with Swing

Rhiannon Liebowitz replied on Wed, 2010/09/15 - 5:49am in response to: Greg Brown

Hi Greg

I will definitely find some time to give apache pivot project a good peruse. The accordion looks pretty nifty, it would be pretty cool seeing a live skinned demo.

Regards

Rhi

Rhiannon Liebowitz replied on Wed, 2010/09/15 - 5:59am in response to: Manuel Jordan

I can't think of any books that deal with that topic directly, it may be a case that they exist and I have just never been exposed to them.

I don't think there is a swing book in existence that would not touch on the MVC pattern though. I think its practically a requirement to discuss the model view controller.

Oracle's jtable and tablemodel are really nice classes to work with. The tableModel's implementation is really flexible and its easy to wrap whatever data you want within the model.

My only real advice to you is that if you are getting data from an external source, be sure to respect the EDT when you supply the new data, and even more so when removing rows!

I wish I could have been more help.

Manuel Jordan replied on Wed, 2010/09/15 - 9:14am in response to: Rhiannon Liebowitz

Hello Rhiannon

I mean no dedicated books for the topics in which I am interesting, I mean at least some chapters dedicated to them

>>I don't think there is a swing book in existence that would not touch on the MVC pattern though.

In your previous book suggestion which cover well this?

Greg Brown replied on Wed, 2010/09/15 - 6:34pm in response to: Rhiannon Liebowitz

That's actually not skinned, it's just styled. The default accordion skin supports most of the styles you would need by default. However, if you needed to go beyond that, you could certainly write a custom skin.

But by all means, please check Pivot out. Hope you find it useful. :-)

G

Rhiannon Liebowitz replied on Fri, 2010/09/17 - 8:41am in response to: Manuel Jordan

Off the top of my head I can't remember how well the MVC was covered in the previous books as its been ages since I read them. I have lent them out to other people, so I can't check them right now. I do know the mvc is always covered though. I actually think you can probably find all the information you need through google. There are tons of pages on swing, mvc and how to do stuff with the table.

If you want a good design pattern book in general, I would go 'Head First Design Patterns', its just so easy to understand. However buying it for information on 1 pattern is probably not worth while.

For a rough idea on mvc and swing you can always start with http://java.sun.com/products/jfc/tsc/articles/architecture/

Manuel Jordan replied on Fri, 2010/09/17 - 4:32pm in response to: Rhiannon Liebowitz

Thanks for the explanation Rhiannon, I hope see more tutorials about swing written by you

Rock Ram replied on Wed, 2010/11/24 - 12:31pm

Hi to all,

 Thank for giving an wonderful article related toswing.

i want to download the javalobby-accordion-skin-demo.jar jar files can anyone help me..

 

Rahul Sapkal replied on Sun, 2014/03/02 - 5:12pm in response to: Rhiannon Liebowitz

Hello Sir, 
     I need this control for my semester project. This is really a useful article on Accordion menu. But I want to know about how to create sub tab menu or options like Inbox,Drafts in Mail  tab. 

  So please can you tell me how to create that sub menu options under tab. Please inform me at rahulvs99@gmail.com. Thank you! 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.