Skip to main content

'Close' icons on a JTabbedPane w/o UI interference

Posted by herkules on October 29, 2005 at 4:18 AM PDT

Many apps require a 'close' icon on a tab of a JTabbedPane. The solutions I've seen so far all require manipulation of the L&F classes which can be considered bad in many respects.

There is another option that works without interference with the UI classes. It relies on a special implementation of Icon that is sensitive to the mouse itself. Such an icon can be set for each tab (setIconAt()). This solution is far from perfect. E.g. the close icon always appears on the left side of the tabs text. But it is simple, easy to use and works with all L&Fs. The schema might be useful in other areas of icon usage as well.

How does it work?

The implementation of CloseTabIcon uses are common Icon and delegates all method calls to it. Just, during paintIcon(), it remembers the last position the icon has been painted and additionally adds a MouseListener to the resp. Component. This mouselistener can test wether the mouse button has been pressed above the icon and perform the appropriate action then.

In order not to loose the possibility to set an icon to the tab that does not close it, I provide another utility class CombinedIcon. It implements Icon and delegates to two Icons given to its constructor. Using CombinedIcon and CloseTabIcon can create JTabbedPanes like this:

[prettify] /*     *   */   package de.hardcode.util.swing;    import java.awt.Component;  import java.awt.Graphics;  import java.awt.Rectangle;  import java.awt.event.MouseAdapter;  import java.awt.event.MouseEvent;  import javax.swing.Icon;  import javax.swing.ImageIcon;  import javax.swing.JTabbedPane;   /**   *   * @author Herkules   */   public class TabCloseIcon implements Icon  {  private final Icon mIcon;  private JTabbedPane mTabbedPane = null;  private transient Rectangle mPosition = null;    /**  * Creates a new instance of TabCloseIcon.  */  public TabCloseIcon( Icon icon )  {  mIcon = icon;  }      /**  * Creates a new instance of TabCloseIcon.  */  public TabCloseIcon()  {  this( new ImageIcon( TabCloseIcon.class.getResource("icons/closeTab.gif")) );  }      /**  * when painting, remember last position painted.  */  public void paintIcon(Component c, Graphics g, int x, int y)  {  if( null==mTabbedPane )  {  mTabbedPane = (JTabbedPane)c;  mTabbedPane.addMouseListener( new MouseAdapter()  {  @Override public void mouseReleased( MouseEvent e )  {  // asking for isConsumed is *very* important, otherwise more than one tab might get closed!  if ( !e.isConsumed()  &&   mPosition.contains( e.getX(), e.getY() ) )  {  final int index = mTabbedPane.getSelectedIndex();  mTabbedPane.remove( index );  e.consume();  }  }  });  }    mPosition = new Rectangle( x,y, getIconWidth(), getIconHeight() );  mIcon.paintIcon(c, g, x, y );  }      /**  * just delegate  */  public int getIconWidth()  {  return mIcon.getIconWidth();  }    /**  * just delegate  */  public int getIconHeight()  {  return mIcon.getIconHeight();  }    } [/prettify]

Find the sourcecode here and a usage sample here.

Related Topics >>


cvs domain changed

Sourceforge change domain names for the cvs access. Please find everything here: