Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures

Home

Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips

Books

Submit News
Search the site here...
Search...
 

Swing Chapter 6. (The basics) Tabbed Panes. Easy for reading, Click here!

Custom Search
Swing Chapter 6. (The basics) Tabbed Panes. Easy for reading, Click here!

[ Return to Swing (Book) ]

Page: 2/3 



Previous Page Previous Page (1/3) - Next Page (3/3) Next Page
Subpages: 1. JTabbedPane
2. Dynamically changeable tabbed pane
3. Customized JTabbedPane and TabbedPaneUI delegate

6.2    Dynamically changeable tabbed pane

We now turn to a JTabbedPane example applet demonstrating dynamically reconfigurable tab layout as well as the addition and removal of any number of tabs. A ChangeListener is attached to the tabbed pane to listen for tab selection events and display the currently selected tab index in a status bar. For enhanced feedback, audio clips are played when the tab layout changes and whenever a tab is added and removed.

Figure 6.1 TabbedPaneDemo

<<file figure6-1.gif>>

The Code: TabbedPaneDemo.java

see \Chapter6\1

import java.awt.*;

import java.applet.*;

import java.awt.event.*;

import javax.swing.*;

import javax.swing.event.*;

import javax.swing.border.*;

public class TabbedPaneDemo extends JApplet

 implements ActionListener

{

  private ImageIcon m_tabimage;

  private ImageIcon m_utsguy;

  private ImageIcon m_jfcgirl;

  private ImageIcon m_sbeguy;

  private ImageIcon m_tiger;

  private JTabbedPane m_tabbedPane;

  private JButton m_topButton;

  private JButton m_bottomButton;

  private JButton m_leftButton;

  private JButton m_rightButton;

  private JButton m_addButton;

  private JButton m_removeButton;

  private JLabel m_status;

  private JLabel m_loading;

  private AudioClip m_layoutsound;

  private AudioClip m_tabsound;

  public void init() {

    m_loading = new JLabel("Initializing applet...",

      SwingConstants.CENTER);

    getContentPane().add(m_loading);

    Thread initialize = new Thread() {

      public void run() {

        m_tabimage = new ImageIcon("tabimage.gif");

        m_utsguy = new ImageIcon("utsguy.gif");

        m_jfcgirl = new ImageIcon("jfcgirl.gif");

        m_sbeguy = new ImageIcon("sbeguy.gif");

        m_tiger = new ImageIcon("tiger.gif");

        m_tabbedPane = new JTabbedPane(SwingConstants.TOP);

        m_topButton = new JButton("TOP");

        m_bottomButton = new JButton("BOTTOM");

        m_leftButton = new JButton("LEFT");

        m_rightButton = new JButton("RIGHT");

        m_addButton = new JButton("add");

        m_removeButton = new JButton("remove");

        m_status = new JLabel();

        Color buttonColor = new Color(245,242,219);

        JPanel buttonPanel = new JPanel();

        buttonPanel.setLayout(new GridLayout(1,6));

        JPanel lowerPanel = new JPanel();

        lowerPanel.setLayout(new BorderLayout());

        m_topButton.setBackground(buttonColor);

        m_bottomButton.setBackground(buttonColor);

        m_leftButton.setBackground(buttonColor);

        m_rightButton.setBackground(buttonColor);

        m_addButton.setBackground(buttonColor);

        m_removeButton.setBackground(buttonColor);

        m_topButton.addActionListener(TabbedPaneDemo.this);

        m_bottomButton.addActionListener(TabbedPaneDemo.this);

        m_leftButton.addActionListener(TabbedPaneDemo.this);

        m_rightButton.addActionListener(TabbedPaneDemo.this);

        m_addButton.addActionListener(TabbedPaneDemo.this);

        m_removeButton.addActionListener(TabbedPaneDemo.this);

        buttonPanel.add(m_topButton);

        buttonPanel.add(m_bottomButton);

        buttonPanel.add(m_leftButton);

        buttonPanel.add(m_rightButton);

        buttonPanel.add(m_addButton);

        buttonPanel.add(m_removeButton);

        buttonPanel.setBackground(buttonColor);

        buttonPanel.setOpaque(true);

        buttonPanel.setBorder(new CompoundBorder(

          new EtchedBorder(EtchedBorder.RAISED),

          new EtchedBorder(EtchedBorder.LOWERED)));

        lowerPanel.add("Center", buttonPanel);

        m_status.setHorizontalTextPosition(SwingConstants.LEFT);

        m_status.setOpaque(true);

        m_status.setBackground(buttonColor);

        m_status.setForeground(Color.black);

        lowerPanel.add("South", m_status);

        createTab();

        createTab();

        createTab();

        createTab();

        getContentPane().setLayout(new BorderLayout());

        m_tabbedPane.setBackground(new Color(245,232,219));

        m_tabbedPane.setOpaque(true);

        getContentPane().add("South", lowerPanel);

        getContentPane().add("Center", m_tabbedPane);

        m_tabbedPane.addChangeListener(new MyChangeListener());

        m_layoutsound = getAudioClip(getCodeBase(), "switch.wav");

        m_tabsound = getAudioClip(getCodeBase(), "tab.wav");

        getContentPane().remove(m_loading);

        getRootPane().revalidate();

        getRootPane().repaint();

      }

    };

    initialize.start();

  }

  public void createTab() {

    JLabel label = null;

    switch (m_tabbedPane.getTabCount()%4) {

      case 0:

        label = new JLabel("Tab #" + m_tabbedPane.getTabCount(),

          m_utsguy, SwingConstants.CENTER);

        break;

      case 1:

        label = new JLabel("Tab #" + m_tabbedPane.getTabCount(),

          m_jfcgirl, SwingConstants.CENTER);

        break;

      case 2:

        label = new JLabel("Tab #" + m_tabbedPane.getTabCount(),

          m_sbeguy, SwingConstants.CENTER);

        break;

      case 3:

        label = new JLabel("Tab #" + m_tabbedPane.getTabCount(),

          m_tiger, SwingConstants.CENTER);

        break;

    }

    label.setVerticalTextPosition(SwingConstants.BOTTOM);

    label.setHorizontalTextPosition(SwingConstants.CENTER);

    label.setOpaque(true);

    label.setBackground(Color.white);

    m_tabbedPane.addTab("Tab #" + m_tabbedPane.getTabCount(),

      m_tabimage, label);

    m_tabbedPane.setBackgroundAt(m_tabbedPane.getTabCount()-1,

      new Color(245,232,219));

    m_tabbedPane.setForegroundAt(m_tabbedPane.getTabCount()-1,

      new Color(7,58,141));

    m_tabbedPane.setSelectedIndex(m_tabbedPane.getTabCount()-1);

    setStatus(m_tabbedPane.getSelectedIndex());

  }

  public void killTab() {

    if (m_tabbedPane.getTabCount() > 0) {

      m_tabbedPane.removeTabAt(m_tabbedPane.getTabCount()-1);

      setStatus(m_tabbedPane.getSelectedIndex());

    }

    else

      setStatus(-1);

  }

  public void setStatus(int index) {

    if (index > -1)

      m_status.setText(" Selected Tab: " + index);

    else

      m_status.setText(" No Tab Selected");

  }

  public void actionPerformed(ActionEvent e) {

    if (e.getSource() == m_topButton) {

      m_tabbedPane.setTabPlacement(SwingConstants.TOP);

      m_layoutsound.play();

    }

    else if(e.getSource() == m_bottomButton) {

      m_tabbedPane.setTabPlacement(SwingConstants.BOTTOM);

      m_layoutsound.play();

    }

    else if(e.getSource() == m_leftButton) {

      m_tabbedPane.setTabPlacement(SwingConstants.LEFT);

      m_layoutsound.play();

    }

    else if(e.getSource() == m_rightButton) {

      m_tabbedPane.setTabPlacement(SwingConstants.RIGHT);

      m_layoutsound.play();

    }

    else if(e.getSource() == m_addButton)

      createTab();

    else if(e.getSource() == m_removeButton)

      killTab();

    m_tabbedPane.revalidate();

    m_tabbedPane.repaint();

  }

  public static void main(String[] args) {

    new TabbedPaneDemo();

  }

  class MyChangeListener implements ChangeListener

  {

    public void stateChanged(ChangeEvent e) {

      setStatus(

        ((JTabbedPane) e.getSource()).getSelectedIndex());

      m_tabsound.play();

    }

  }

}

Understanding the Code

Class TabbedPaneDemo

TabbedPaneDemo extends JApplet and implements ActionListener (to listen for button events). Several instance variables are used:

ImageIcon m_tabimage: image used in each tab extension.

ImageIcon m_utsguy, m_jfcgirl, m_sbeguy, m_tiger: images used in tab containers.

JTabbedPane m_tabbedPane: the main tabbed pane.

JButton m_topButton: TOP tab alignment button.

JButton m_bottomButton: BOTTOM tab alignment button.

JButton m_leftButton: LEFT tab alignment button.

JButton m_rightButton: RIGHT tab alignment button.

JButton m_addButton: add tab button.

JButton m_removeButton: remove tab button.

JLabel m_status: status bar label.

Our JTabbedPane, tabbedPane, is created with TOP tab alignment. (Note: TOP is actually the default so this is really not necessary here.  The default JTabbedPane constructor would do the same thing.)

The init() method organizes the buttons inside a JPanel using GridLayout, and associates ActionListeners with each one. We wrap all instantiation and GUI initialization processes in a separate thread and start it in the this method. This is because loading can take several seconds and it is best to allow the interface to be as responsive as possible during this time. We also provide an explicit visual cue to the user that the application is loading by placing an "Initializing applet..." label in the content pane where the tabbed pane will be placed once initialized. In this initialization, our createTab() method (discussed below) is called four times. We then add the panel containing the tabbed pane controller buttons, and our tabbed pane to the contentPane. Finally, an instance of MyChangeListener (see below) is attached to our tabbed pane to listen for tab selection changes.

The createTab() method is called whenever m_addButton is clicked. Based on the current tab count this method chooses between four ImageIcons, creates a JLabel containing the chosen icon, and adds a new tab containing that label.  The killTab() method is called whenever m_removeButton is clicked to remove the tab with the highest index.

The setStatus() method is called each time a different tab is selected.  The m_status JLabel is updated to reflect which tab is selected at all times.

The actionPerformed() method is called whenever any of the buttons are clicked.   Clicking m_topButton, m_bottomButton, m_leftButton, or m_rightButton causes the tab layout of the JTabbedPane to change accordingly using the setTabPlacement() method.   Each time one of these tab layout buttons is clicked a WAV file is played.  Similarly, when a tab selection change occurs a different WAV file is invoked. These sounds, m_tabsound and m_layoutsound, are loaded at the end of the init() method:

    m_layoutsound = getAudioClip(getCodeBase(), "switch.wav");

    m_tabsound = getAudioClip(getCodeBase(), "tab.wav");

Before the actionPerformed() method exits it revalidates the JTabbedPane. (If this revalidation is omitted we would see that a layout change caused by clicking one of our tab layout buttons will result in incorrect tabbed pane rendering.)

Class TabbedPaneDemo.MyChangeListener

MyChangeListener implements the ChangeListener interface.  There is only one method that must be defined when implementing this interface: stateChanged().  This method can process ChangeEvents corresponding to when a tabbed pane's selected state changes.  In our stateChanged() method we update the status bar in TabbedPaneDemo and play an appropriate tab switching sound:

    public void stateChanged(ChangeEvent e) {

      setStatus(

        ((JTabbedPane) e.getSource()).getSelectedIndex());

      m_tabsound.play();

    }

Running the Code:

Figure 6.1 shows TabbedPaneDemo in action. To deploy this applet the following simple HTML file is used (this is not Plug-in compliant):

<applet code=TabbedPaneDemo width=570 height=400> </applet>

Add and remove some tabs, and play with the tab layout to get a feel for how it works in different situations.  Note that you can use your arrow keys to move from tab to tab (if the focus is currently on a tab), and remember to turn your speakers on for the sound effects.

Note: You may have problems with this applet if your system does not support .wav files.  If so, comment out the audio-specific code and recompile.

6.2.1    Interesting JTabbedPane characteristics

In cases where there is more than one row or column of tabs most of us are used to the following functionality:  selecting a tab that is not in the frontmost row or column moves that row or column to the front.  This does not occur in a JTabbedPane using the default Metal L&F as can be seen in the TabbedPaneDemo example above.  However, this does occur when using the Windows, Motif, and Basic L&Fs. This feature was purposefully disabled in the Metal L&F (as can be verified in the MetalTabbedPaneUI source code).

UI Guideline : Avoid Multiple Rows of Tabs

As a general rule, you should seek to design for no more than a single row or column of tabs.
There are three key reasons for this. The first is a cognitive reason: the user has trouble discerning what will happen with the multiple rows of tabs. With Windows L&F for example, the behaviour somewhat mimics the behaviour of a rolladex filing card system. For some Users this mental model is clear and the behaviour is natural, for others it is simply confusing.

The second reason is a human factors / usability problem. When a rear set of tabs comes to the front, as with Windows Look and Feel, the position of all the other tabs changes. This means that the User has to discern the new position of a tab before visually selecting it and moving the mouse toward it. This has the effect of denying the User the ability to learn the positions of the tabs. Directional memory is a strong attribute and highly productive for usability. Thus it is always better to keep the tabs in the same position. This was the reason that the Sun and Apple designers chose to implement multiple tabs in this fashion! The final reason is a design problem. When a second or subsequent row or column of tabs is introduced, there is a resizing of the tabbed pane itself. Although, the layout manager will cope with this, it may not look visually satisfactory when completed. The size of the tabbed pane becomes dependant on the ability to render the tabs in a given space. Those who remember the OS2 Warp UI will recall that the designers avoided this problem by allowing only a single row of tabs and the ability to scroll them if they didn't fit into the given space. So far no one has implemented a Swing L&F with this style of tabbed pane.



[ Return to Swing (Book) ]


Top 10 read Java Articles
 Get free "1000 Java Tips eBook"

 Java Calendar and Date: good to know facts and code examples

 Array vs ArrayList vs LinkedList vs Vector: an excellent overview and examples

 How can I convert any Java Object into byte array? And byte array to file object

 The Java Lesson 1: What is Java?

 How do I compare two dates and times, date between dates, time between times and

 Maven vs Ant or Ant vs Maven?

 How to open, read, write, close file(s) in Java? Examples on move, rename and de

 Java Array

 Java: JLabel font and color


[ More in News Section ]
Java Lessons

The Java Lesson 1:
What is Java?
The Java Lesson 2:
Anatomy of a simple Java program
The Java Lesson 3:
Identifiers and primitive data types
The Java Lesson 4:
Variables, constants, and literals
The Java Lesson 5:
Arithmetic operations, conversions, and casts
The Java Lesson 6:
Boolean expressions and operations
The Java Lesson 7:
Bitwise operations
The Java Lesson 8:
Flow control with if and else
The Java Lesson 9:
switch statements
The Java Lesson 10:
for, while, and do-while statements
The Java Lesson 11:
Using break and continue
The Java Lesson 12:
Class methods and how they are called
The Java Lesson 13:
Using the Math class
The Java Lesson 14:
Creating and calling custom class methods
The Java Lesson 15:
Overloading class methods
The Java Lesson 16:
An introduction to objects and object references
The Java Lesson 17:
The String class
The Java Lesson 18:
The StringBuffer class
The Java Lesson 19:
Initializing and processing arrays of primitives
The Java Lesson 20:
Initializing and processing arrays of objects
The Java Lesson 23:
Inheritance and overriding inherited methods
The Java Lesson 24:
abstract classes and polymorphism
The Java Lesson 25:
Interfaces, instanceof, and object conversion and casting
The Java Lesson 26:
Introduction to graphical programming and the java.awt packa
The Java Lesson 27:
The Component class
The Java Lesson 28:
Containers and simple layout managers
The Java Lesson 29:
The Color and Font classes
The Java Lesson 30:
Drawing geometric shapes
The Java Lesson 31:
Choice, List, and Checkbox controls
The Java Lesson 32:
Using the Scrollbar graphical control
The Java Lesson 33:
Menus and submenus
The Java Lesson 34:
An introduction to applets and the Applet class
The Java Lesson 35:
Essential HTML to launch an applet and pass it parameters
The Java Lesson 36:
Mouse event processing
Java Lesson 37:
Menus and submenus
Java Lesson 38:
The WindowListener interface and the WindowAdapter class
Java Lesson 39:
An introduction to GridBagLayout
Java Lesson 40:
An introduction to the Java Collections API
Java Lesson 41:
Exception handling with try, catch, and finally blocks
Java Lesson 42:
Claiming and throwing exceptions
Java Lesson 43:
Multithreading, the Thread class, and the Runnable interface
Java Lesson 44:
An introduction to I/O and the File and FileDialog classes
Java Lesson 45:
Low-level and high-level stream classes
Java Lesson 46:
Using the RandomAccessFile class
Java Lessons by
Joh Huhtala: Update

Latest articles
 Java Profiler JProbe to Resolve Performance Problems Faster

 SSL with GlassFish v2, page 5

 SSL with GlassFish v2, page 4

 SSL with GlassFish v2, page 3

 SSL with GlassFish v2, page 2

 The Java Lesson 2: Anatomy of a simple Java program, page 2

 New site about Java for robots and robotics: both software and hardware.

 Exceptions -III: What's an exception and why do I care?

 Exceptions -II: What's an exception and why do I care?

 Exceptions: What's an exception and why do I care?

 Double your Java code quality in 10 minutes, here is receipt

 Murach's Java Servlets and JSP

 How to get ascii code from a char in Java?

 Can we just try without catch? Yes!

 Make Tomcat page load faster

 Make your Tomcat More secure - limit network address for certain IP addresses

 New Java book online starts now here...

 Implementing RESTful Web Services in Java

 Firefox trimming from 1 GB to 40 Mb with many tabs opened

 SSL with GlassFish v2

 My request to replublish Tech Tips

 Search JavaFAQ.nu site here

 New Advanced Installer for Java 6.0 brings XML updates and imports 3rd party MSI

 EJB programming restrictions

 Maven vs Ant or Ant vs Maven?

 Why Java does not use default value which it should?

 How to unsign signed bytes in Java - your guide is here

 The Java Lesson 3: Identifiers and primitive data types. Page 2

 The Java Lesson 7: Bitwise operations with good examples, click here! Page 4

 The Java Lesson 7: Bitwise operations with good examples, click here! Page 3


[ More in News Section ]


Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

RSS feed Java FAQ RSS feed Java FAQ News     

    RSS feed Java Forums RSS feed Java Forums

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

Interactive software released under GNU GPL, Code Credits, Privacy Policy