Skip to main content

JTabbedPane tab components

1 reply [Last post]
Joined: 2003-06-16

First, thank you for adding the "arbitrary tab components" feature to JTabbedPane. Finally we'll have a good answer for all the people who ask in the forums how to add close buttons to their tabs!

I've been playing with this feature for several days now, and I'd like to share some issues I've encountered. I'll submit bug reports if they're called for, but I want to get some feedback first, and also discover whether these issues are already being worked on. The sample code below demonstrates what I'm talking about.

The UI delegate uses an Insets object to position the tab's contents within the tab. This margin works well enough for the icon+text label that JTabbedPane has always used, but it isn't necessarily right for an arbitrary tab component. For example, the close buttons in the sample program should be right near the edges of the tabs, but the default Insets adds an unsightly gap--in the case of Metal L&F, a whopping nine pixels' worth. It also leaves no gap at all between the top of the button and the tab's top border. These defaults can be overridden easily enough, as shown in the main() method below, but that's no solution: they would need to be overridden differently depending on both the L&F and the tab positions. It seems to me the UI delegate should generate a minimal Insets for use with user-supplied tab components, taking into account any L&F-specific issues like the extra six pixels needed at whichever end has the corner notch under Metal/Ocean.

Opaque components
The javadoc should caution users to always use transparent tab components. I originally used a JPanel as the basis of my tab components, but the selected tab looked really screwed up until I added a call to setOpaque(false). (The default FlowLayout also adds a lot of unwanted padding; Box seems to be the ideal container for tab components.)

When I first run the sample program, there are no focus indicators visible anywhere, pressing the Tab key or the spacebar has no effect, and traversing the tabs with Ctrl-Tab (Windows) or the arrow keys (Metal) doesn't work. If I close a tab by clicking on its close button, one of the remaining close buttons gets the keyboard focus. Thereafter the tab traversal keys work correctly, and pressing the Tab key cycles the focus through all the remaining close buttons plus the selected tab. If I uncomment the "setFocusable" line (which should only affect the buttons), keyboard focus and tab traversal never work at all. Actually, the issue doesn't seem to be specific to tab components, because if I comment out the "setTabComponentAt" line, they still don't work (but they work if I run the program under jdk 1.5). Is this a bug, or am I doing something wrong?

Finally, I can't help wondering why JTabbedPane didn't just use a JLabel to render the tabs from the beginning? It seems like it would have made things so much easier...

import java.awt.*;<br />
import java.awt.event.*;<br />
import javax.swing.*;</p>
<p>public class Test<br />
{<br />
  public Test()<br />
  {<br />
    JTabbedPane tp = new JTabbedPane();</p>
<p>    String[] fillers = new String[] { "One", "Two", "Three", "Four"  };<br />
    for (String str : fillers)<br />
    {<br />
      JLabel comp = new JLabel("" + str + "");<br />
      comp.setHorizontalAlignment(JLabel.CENTER);<br />
      comp.setForeground(Color.BLUE);<br />
      tp.add(str, comp);<br />
      tp.setTabComponentAt(tp.indexOfComponent(comp),<br />
                           createTabComponent(tp, comp, str));<br />
<p>    JFrame frame = new JFrame("JTabbedPane Test");<br />
    frame.add(tp);<br />
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />
    frame.setSize(new Dimension(400, 150));<br />
    frame.setLocationRelativeTo(null);<br />
    frame.setVisible(true);<br />
<p>  private JComponent createTabComponent(final JTabbedPane tp,<br />
                                        final Component comp,<br />
                                        String title)<br />
  {<br />
    JButton btn = new JButton("X");<br />
//    btn.setFocusable(false);<br />
    btn.setForeground(Color.RED);<br />
    btn.setMargin(new Insets(0, 2, 0, 1));<br />
    btn.addActionListener(<br />
      new ActionListener()<br />
      {<br />
        public void actionPerformed(ActionEvent evt)<br />
        {<br />
          tp.remove(comp);<br />
        }<br />
      }<br />
<p>    JComponent tabComp = Box.createHorizontalBox();<br />
    tabComp.add(new JLabel(title));<br />
    tabComp.add(Box.createHorizontalStrut(6));<br />
<p>    return tabComp;<br />
<p>  public static void main(String[] args)<br />
  {<br />
    /* Insets for Metal/Ocean L&F - default is (0, 9, 1, 9) */<br />
    UIManager.put("TabbedPane.tabInsets", new Insets(1, 6, 1, 1));</p>
<p>//    try<br />
//    {<br />
//      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());<br />
//    }<br />
//    catch (Exception ex)<br />
//    {<br />
//      ex.printStackTrace();<br />
//    }<br />
//    /* Insets for Windows (XP) L&F - default is (0, 4, 1, 4) */<br />
//    UIManager.put("TabbedPane.tabInsets", new Insets(1, 4, 1, 1));</p>
<p>    new Test();<br />

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Joined: 2004-04-21

Related to tabbed panes could we get Tim's tab component pulled out of Netbeans and officially put in the JRE? The code is written. It just needs a little cleanup. Keep JTabbedPane, just give me a model driven alternative. I pulled it out once already...

However, the Netbeans code has moved forward again to the point Tim's build scripts don't work.