The JTabbedPane Class

If you’ve ever right-clicked on the desktop to set your Display Properties in Windows, you already know what a JTabbedPane is. It’s a container with labeled tabs (e.g., Themes, Screen Saver, Appearance). When you click on a tab, a new set of controls is shown in the body of the JTabbedPane. In Swing, JTabbedPane is simply a specialized container.

Each tab has a name. To add a tab to the JTabbedPane, simply call addTab(). You’ll need to specify the name of the tab as well as a component that supplies the tab’s contents. Typically, it’s a container holding other components.

Even though the JTabbedPane only shows one set of components at a time, be aware that all the components on all the pages are alive and in memory at one time. If you have components that hog processor time or memory, try to put them into a “sleep” state when they are not showing.

The following example shows how to create a JTabbedPane. It adds standard Swing components to a tab named Controls. The second tab is filled with a scrollable image, which was presented in the previous examples.

    //file: TabbedPaneFrame.java
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.border.*;

    public class TabbedPaneFrame {
      public static void main(String[] args)
      {
        JFrame frame = new JFrame("TabbedPaneFrame");
        JTabbedPane tabby = new JTabbedPane();

        // create the controls pane
        JPanel controls = new JPanel();
        controls.add(new JLabel("Service:"));
        JList list = new JList(
            new String[] { "Web server", "FTP server" });
        list.setBorder(BorderFactory.createEtchedBorder());
        controls.add(list);
        controls.add(new JButton("Start"));

        // create an image pane
        String filename = "Piazza di Spagna.jpg";
        JLabel image = new JLabel( new ImageIcon(filename) );
        JComponent picture = new JScrollPane(image);
        tabby.addTab("Controls", controls);
        tabby.addTab("Picture", picture);

        frame.getContentPane().add(tabby);

        frame.setSize(200, 200);
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setVisible(true);
      }
    }

The code isn’t especially fancy, but the result is an impressive-looking user interface. The first tab is a JPanel that contains some other components, including a JList with an etched border. The second tab simply contains the JLabel with ImageIcon wrapped in a JScrollPane. The running example is shown in Figure 17-11.

Our example has only two tabs and they fit quite easily, but in a realistic application it is easy to run out of room. By default, when there are too many tabs to display in a single row, JTabbedPane automatically wraps them into additional rows. This behavior fits with the tab notion quite well, giving the appearance of a filing cabinet, but it also necessitates that when you select a tab from the back row, the tabs must be rearranged to bring the selected tab to the foreground. Many users find this confusing, and it violates a principal of user interface design that says that controls should remain in the same location. Alternatively, you can configure the tabbed pane to use a single, scrolling row of tabs by specifying a scrolling tab layout policy like this:

    setTabLayoutPolicy( JTabbedPane.SCROLL_TAB_LAYOUT );
Using a tabbed pane

Figure 17-11. Using a tabbed pane

Java 6 introduced the ability to add custom components to tabs. The most common use of this capability is the addition of buttons on tabs for functions such as close, info, tear away, etc. The following example demonstrates how to use the new setTabComponentAt(int index, Component component) method to add a close button on each tab.

    //file: ClosableTabs.java
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    
    public class ClosableTabs extends JTabbedPane {    
        
        public void addTab(String title, Color color) {
            JPanel pane = new JPanel();
            pane.setBackground(color);
            int loc = getTabCount();
            insertTab(title, null, pane, null, loc);
            setTabComponentAt(loc, new Tab(title));
        }
        
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable(){
                public void run(){
                    JFrame frame = new JFrame("Closable Tabs");
                    
                    ClosableTabs tabs = new ClosableTabs();
                    tabs.addTab("Blue", Color.BLUE);
                    tabs.addTab("Green", Color.GREEN);
                    tabs.addTab("Red", Color.RED);
                    frame.add(tabs);
                    
                    frame.setDefaultCloseOperation(
                        JFrame.EXIT_ON_CLOSE);
                    frame.setSize(new Dimension(300, 150));
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }});
        }
        
        /**
         * The component used as a tab (i.e., the tab itself as opposed 
         * to the content)
         */
        private class Tab extends JPanel {
         
            public Tab(String title) {
                super(new FlowLayout(FlowLayout.LEFT, 0, 0));
                setOpaque(false);
                 
                // The tab's title
                JLabel label = new JLabel(title);
                
                // Creating a space to the right of the close button
                label.setBorder(BorderFactory.createEmptyBorder(0, 0, 
                    0, 2));
    
                add(label);
                
                // The tab's close button
                JButton button = new CloseButton();
                add(button);
    
                // This is necessary for vertical alignment of the 
                // tab's content
                setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
            }
         
            private class CloseButton extends JButton
                implements ActionListener {
                
                public CloseButton() {
                    setPreferredSize(new Dimension(17, 17));
                    setOpaque(false);
                    setContentAreaFilled(false);
                    setBorderPainted(false);
                    setRolloverEnabled(true);
                    setFocusable(false);
                    addActionListener(this);
                }
         
                public void actionPerformed(ActionEvent e) {
                    int i = ClosableTabs.this.indexOfTabComponent(
                        Tab.this);
                    if (i != -1) {
                        ClosableTabs.this.remove(i);
                    }
                }
         
                protected void paintComponent(Graphics g) {
                    Graphics2D g2 = (Graphics2D)g;
                    g2.setStroke(new BasicStroke(2));
                    
                    // Show red on roll-over
                    g2.setColor(Color.BLACK);
                    if (getModel().isRollover()) {
                        g2.setColor(Color.RED);
                    }
                    
                    // Paint the "X"
                    int offset = 5;
                    g2.drawLine(offset, offset, getWidth() - 
                        offset - 1, getHeight() - offset - 1);
                    g2.drawLine(getWidth() - offset - 1, offset, 
                        offset, getHeight() - offset - 1);
                    g2.dispose();
                }
            }
        }
    }

Get Learning Java, 4th Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.