Skip to main content

TabComponents in action

Posted by alexfromsun on November 9, 2005 at 10:51 AM PST

It's been a lot of publications about adding "close" button to a tabbedPane, all solutions suggested are really inventive and not easy to find. But we are gonna talk about Mustang "tabComponents feature" because it is the most preferable and clear solution for JTabbedPane customizing.

Since 1.6 three new methods added to JTabbedPane:

we can put a component to a tab with help of
public void setTabComponentAt(int index, Component component)

get this component with
public Component getTabComponentAt(int index)

and test if a component is a tabComponent for this JTabbedPane with
public int indexOfTabComponent(Component tabComponent)

With this three methods we can enrich a JTabbedPane with comboboxes, multiple labels or whatever we want.
Remember that JTabbedPane's tab area is not a real component, it is just an image so to insert a component there we can can draw a fake component in addition to the existing tab's title (it was the only solution before Mustang) or set our own tabComponent which can draw title and icon and contain any other additional components.

Please download source files and go on.

First, let's check how we can add the most wanted “close” buttons to a JTabbedPane

TabComponent with a “close” button

(source files in the blog.test1 package)

I sublcassed JPanel and added there JLabel to show tab's title and a customized button which can close this tab – and that's it !

Here how it looks:

Notice that we use a real JButton here so we can set a tooltip, attach an ActionListener and customise it in any ways

The only new thing is the close button's actionListener:

        public void actionPerformed(ActionEvent e) {
            int i = pane.indexOfTabComponent(ButtonTabComponent.this);
            if (i != -1) {
                pane.remove(i);
            }
        }

When we click to this button we find the index of the tab this button belongs to and close the tab.

The only possible problem is that this tabComponent doesn't respect actual JTabbedPane's titles so if we remove all tabComponents
(with help of "Options" menu from the test) we'll see:

JTabbedPane without tabComponents

Notice that actual tab's titles looks like tab1 not like tabComponent1.

In the next example we'll easily create better tabComponent which can show the actual titles.

JRadioButton as a tabComponent

(source files in the blog.test2 package)

Let's say we don't like JTabbedPane's focus rendering and want to replace it with something else.
For example we like JRadioButtons and want them to render font and focus for the tabs.
We can easily achieve that:

With this code:

        JRadioButton button = new JRadioButton() {
            //This way we always have up-to-date tab's title 
            public String getText() {
                int i = pane.indexOfTabComponent(this);
                if (i != -1) {
                    return pane.getTitleAt(i);
                }
                return null;
            }
        };

our radioButton will alway show the actual tab's title.

We only need to add one listener to radioButtons to select a tab when we select a JRadioButton
and one listener to JTabbedPane to do the opposite - select proper radioButton when we select a tab.

Crazy tabComponent with two icons

(source files in the blog.test3 package)

It is possible to show not only a title from a tab, but an icon as well.
Just for fun I created a big tabComponent which shows a title between to identical icons:

if we remove all tabComponents we'll see that actual title and actual icon are used:

We find the acual icon just like we find titles for the previous example

Conclusion

TabComponents make it possible to customise JTabbedPane component quite easily,
please try the latest Mustang build and create your own tabComponents !

let me give you some recommendations

  1. Keep in mind that tabs are not a real components just an image,
    so it is good idea to use components with setOpaque(false) to see tab's decorations underneath.
  2. Use proper spacing around your tabComponents, because big opaque component may overlap tab's decorations.
  3. To be on the safe side, test your tabComponents for all LaF's you
    use in your application (for WRAP_TAB_LAYOUT and SCROLL_TAB_LAYOUT).
  4. If you need to add a listener to your tabComponents, create the only instance of a listener and share it between all tabComponents
  5. Remember that only components without MouseListeners and MouseMotionListeners are transparent for mouse events. To be on the safe side use additional mouseListener which will select a proper tab when you click on tabComponent.
    For more information about that see my previous blog

Thanks
Alex

Related Topics >>