Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / May 2005

Tip: Looking for answers? Try searching our database.

Closable Tabs in JTabbedPane

Thread view: 
Dan Andrews - 31 Mar 2004 15:50 GMT
Yesterday I thought see what I could find on "Closable Tabs in
JTabbedPane". Our own framework library at work did not have anything
useful and neither our COTS libraries. A quick search of the group was
equally unhelpful. At any rate here is a long overdue contribution
that I threw together as a quick investigation of how this could be
done; although, there is likely a more elegant solution out there
still. I have tried to capture the platform look and feel without too
many dependencies on the UI classes. I have found, in general, that
however much fun it can be (NOT) playing with custom UI classes or UI
hacks are often broken with new releases of the JDK.

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.JButton;
import javax.swing.JComponent;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;

/**
* A closeable tabbed pane icon.
* @author Dan Andrews          www.dotjava.ca
*/
public class TabbedPaneCloseIcon
   extends MouseAdapter
   implements Icon
{

   private static final int INSET = 2;
   private static final JButton BORDER_WORKER = new JButton();
   /** The UI's close icon */
   private Icon _closeIcon = UIManager.getIcon(
       "InternalFrame.closeIcon" );

   /** The tab that this icon is used in */
   private JTabbedPane _parentTabbedPane;

   /** The JComponent tab to be closed if required */
   private JComponent _tabbedComponent;

   /** This icons bounds in the JTabbedPane object */
   private Rectangle _bounds = new Rectangle();

   /**
    * Constructor.
    * @param parentTabbedPane
    * @param tabbedComponent
    */
   public TabbedPaneCloseIcon( JTabbedPane parentTabbedPane,
           JComponent tabbedComponent )
   {

       _parentTabbedPane = parentTabbedPane;
       _tabbedComponent = tabbedComponent;

       parentTabbedPane.addMouseListener( this );
   }

   /**
    * Gets the close icon's height.
    * @return the height
    */
   public int getIconHeight()
   {
       return _closeIcon.getIconHeight();
   }

   /**
    * Gets the close icon's width.
    * @return the width
    */
   public int getIconWidth()
   {
       return _closeIcon.getIconWidth();
   }

   /**
    * Mouse clicked check to close tab if required.
    * @param e IN the MouseEvent object.
    */
   public void mouseClicked( MouseEvent e )
   {

       if( _bounds.contains( e.getX(), e.getY() ) )
       {
           _parentTabbedPane.remove( _tabbedComponent );
       }
   }

   /**
    * Paints the icon using the platform InternalFrame.closeIcon.
    * Note this assumes it is in a button and paints relative to
    * x = 0, and y = 0.
    * @param c IN not used
    * @param g IN the Graphics object
    * @param x IN the x bounds location and used for translation
    * @param y IN the y bounds location and used for translation
    */
   public void paintIcon( Component c, Graphics g, int x, int y )
   {

       _bounds.width = getIconWidth();
       _bounds.height = getIconHeight() - INSET;
       _bounds.x = x;
       _bounds.y = y + INSET;

       BORDER_WORKER.getBorder().paintBorder(
               BORDER_WORKER, g, _bounds.x,
               _bounds.y, _bounds.width, _bounds.height );
       g.translate( x - 1, _bounds.y );
       _closeIcon.paintIcon( BORDER_WORKER, g, 0, 0 );
       g.translate( -( x - 1 ), -_bounds.y );
   }
}

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;

/**
* FrmTest
*/
public class FrmTest
   extends JFrame
{

   private JPanel _pnlMain = new JPanel();
   private BorderLayout _borderLayout1 = new BorderLayout();
   private JTabbedPane jTabbedPane1 = new JTabbedPane();
   private JPanel jPanel1 = new JPanel();
   private JPanel jPanel2 = new JPanel();
   private JPanel jPanel3 = new JPanel();
   private JPanel jPanel4 = new JPanel();
   private JPanel jPanel5 = new JPanel();

   /**
    * Constructor
    */
   public FrmTest()
   {

       try
       {
           jbInit();
           setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
           jTabbedPane1.insertTab( "jPanel1",
                   new TabbedPaneCloseIcon( jTabbedPane1, jPanel1 ),
                   jPanel1, null, 0 );
           jTabbedPane1.insertTab( "jPanel2",
                   new TabbedPaneCloseIcon( jTabbedPane1, jPanel2 ),
                   jPanel2, null, 1 );
           jTabbedPane1.insertTab( "jPanel3",
                   new TabbedPaneCloseIcon( jTabbedPane1, jPanel3 ),
                   jPanel3, null, 2 );
           jTabbedPane1.insertTab( "jPanel4",
                   new TabbedPaneCloseIcon( jTabbedPane1, jPanel4 ),
                   jPanel4, null, 3 );
           jTabbedPane1.insertTab( "jPanel5",
                   new TabbedPaneCloseIcon( jTabbedPane1, jPanel5 ),
                   jPanel5, null, 4 );
       }
       catch( Exception e )
       {
           e.printStackTrace();
       }
   }

   /**
    * JBuilder initialization
    * @throws Exception
    */
   private void jbInit()
       throws Exception
   {

       _pnlMain.setLayout( _borderLayout1 );
       this.getContentPane().add( _pnlMain, BorderLayout.CENTER );
       _pnlMain.add( jTabbedPane1, BorderLayout.CENTER );
   }

   /**
    * Main method
    * @param args IN not used
    */
   public static void main( String[] args )
   {

       try
       {
           UIManager.setLookAndFeel(
               "javax.swing.plaf.metal.MetalLookAndFeel" );
           createShowFrame( "Metal", 100, 100 );
           UIManager.setLookAndFeel(
               "com.sun.java.swing.plaf.motif.MotifLookAndFeel" );
           createShowFrame( "Motif", 120, 200 );
           UIManager.setLookAndFeel(
             "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
           createShowFrame( "Windows", 140, 300 );
       }
       catch( Exception e )
       {
           e.printStackTrace();
       }
   }

   /**
    * Shows the frame with the given title
    */
   private static void createShowFrame( String title, int x, int y )
   {

       FrmTest frame = new FrmTest();
       Dimension screenSize =
           Toolkit.getDefaultToolkit().getScreenSize();
       Dimension frameSize = frame.getSize();

       frameSize.height = 400;
       frameSize.width = 400;

       frame.setTitle( title );
       frame.setSize( frameSize );
       frame.setLocation( x, y );
       frame.setVisible( true );
   }
}

-----Original Message-----

From: lamba (lambavinod@yahoo.co.in)
Subject: Closable tab in JTabbedPane
This is the only article in this thread
View: Original Format
Newsgroups: comp.lang.java.programmer
Date: 2003-04-11 03:28:48 PST

I trying to develop a Closable Tab in JTabbedPane. The close button
should appear after/before the tab title all the time (like in
JBuilder IDE).
   I know the trick where close button appears when the mouse is in
that area, but i want it to be displayed all the time irrespective of
the mouse position.

  How i should be able to create this component??

  I am very new to swing please help...
Alan Moore - 01 Apr 2004 15:19 GMT
>Yesterday I thought see what I could find on "Closable Tabs in
>JTabbedPane". Our own framework library at work did not have anything
[quoted text clipped - 6 lines]
>however much fun it can be (NOT) playing with custom UI classes or UI
>hacks are often broken with new releases of the JDK.

Unfortunately, they've managed to break it anyway, despite your
precautions.  When I run this code under Tiger-beta1, it comes out
thoroughly mangled in all three L&F's.  Apparently, it's the new Ocean
theme causing that, because if I comment out the lines that create the
Metal example, the other two paint okay.  However, the Motif example
can't seem to find the specified icon (but if I click on the tiny
square that it paints instead, it does close the tab).  The Windows
example is a little flaky, in that the close buttons don't always work
the first time I click them.  (It also tends to throw NPE's, but
that's due to a bug I've already reported.)

Under 1.4.2, the close buttons don't work if you use the
SCROLL_TAB_LAYOUT option.  And, of course, there's no way to make it
paint the icon to the right of the text (where it belongs, IMO).  This
is the most elegant attempt I've seen at solving this problem, but
you're trying to do the impossible.  There isn't going to be a
satisfactory solution until they rewrite JTabbedPane from scratch.  In
fact, they said they were going to do just that for Tiger, but they
seem to have reneged on that promise.
Dan Andrews - 05 Apr 2004 15:57 GMT
> Under 1.4.2, the close buttons don't work if you use the
> SCROLL_TAB_LAYOUT option.  And, of course, there's no way to make it
[quoted text clipped - 4 lines]
> fact, they said they were going to do just that for Tiger, but they
> seem to have reneged on that promise.

Thanks for the comments. There is another minor problem that I have
noticed too. When closing a tab you will need to remove the mouse
listener.

   /**
    * Mouse clicked check to close tab if required.
    * @param e IN the MouseEvent object.
    */
   public void mouseClicked( MouseEvent e )
   {

       if( _bounds.contains( e.getX(), e.getY() ) )
       {
           // *Remove* the listener
           _parentTabbedPane.removeMouseListener( this );  
           _parentTabbedPane.remove( _tabbedComponent );
       }
   }
Alan Moore - 06 Apr 2004 14:42 GMT
>Thanks for the comments. There is another minor problem that I have
>noticed too. When closing a tab you will need to remove the mouse
[quoted text clipped - 14 lines]
>        }
>    }

What I prefer to do is to put a Close button in the toolbar, way over
at the right end (under the window-close button), that closes
whichever tab is on top.  I also have a mouse listener that brings up
a popup menu whenever the user right-clicks on a tab.  Choosing the
Close menuitem lets the user close that pane without bringing it to
the top first. (I actually have to use the low-level processMouseEvent
method to achieve that.)  Having a Close button in every tab has
always seemed like a waste of space to me anyway.
chrismurphy - 18 May 2005 18:21 GMT
Hi Alan,

Would you be able to post that low-level processMouseEvent method you
mentioned? I'm up to the same place myself and well, if someone else has
already done it ...

thanks - Chris Murphy
winslave - 06 Apr 2004 19:33 GMT
Well I've done this by extending ImageIcon (similar to the code
you provided) and JPanel
and adding a mouse listener to the JTabbedPane.
My custom JPanel has a getCloseIcon() method used to get a reference
to the close icon. In the  mouseClicked
event I do a
public void mousePressed(MouseEvent e) {
        try{
        MyFilePanel mfp=(MyFilePanel)tabbedPane.getSelectedComponent();
        MyTabXIcon mtx=mfp.getCloseIcon();
        if(mtx.getBounds().contains(e.getPoint()))
        {
            tabbedPane.remove(tabbedPane.getSelectedIndex());
            }
        }catch(Exception ex){}
    }

> > Under 1.4.2, the close buttons don't work if you use the
> > SCROLL_TAB_LAYOUT option.  And, of course, there's no way to make it
[quoted text clipped - 23 lines]
>         }
>     }


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.