# 4

# JCTabButton and JCTabManager

Introduction · Sample Program Code · Changing the Active Tab

Controlling Tab Display · Tab Button Properties · Events

Property Listing · Example Program

## Introduction

Tabbed dialogs enable the programmer to create a "layer" of dialogs which the user can access through a set of tabs. Based on the visual metaphor of a sequence of file folders, users click a tab to display the contents of a specific file folder. Tabbed dialogs provide an easy way to provide users with a convenient and intuitive way of accessing options contained within with a well-organized interface.

The Java Development Kit (JDK) does not implement tab dialogs. `JCTabButton` dialogs look and behave like their MS Windows 95 equivalents. `JCTabButton` dialogs are created and controlled by `JCTabManager`, which is a container that organizes its children into pages to simulate a sequence of file folders. The page components are defined as children of the `JCTabManager`; a property is then used to associate a page with a particular tab button. Page components can be of any class (including any container). The tabs are subclassed from `JCButton`, which can contain multiple lines of text, images, or contain both text and images. `JCTabButton` dialogs use the new event model to update the tabbed page display.

#### Behavior

`JCTabButton` dialogs behave in the following manner:

- if a tab is clicked, the tab and its associated page is brought to the front, and any text appearing in the tab is rendered in a bold font
- while the tab has focus, a border appears around its label
- tabs can be traversed using the cursor keys
- the TAB key can be used to traverse between the active tab and the contents of its page.

## Sample Program Code

To program tabbed dialogs, you need to create the following:

- a Tab Manager container (`JCTabManager`) to control the display and organization of tabs
- one or more Tab Button component(s) (`JCTabButton`) to define tabs for your dialog
- page components to be stored in the tabbed dialog.

Together, the `JCTabManager` and `JCTabButton` simulate a sequence of file folders. The page components are defined as children of the `JCTabManager`; a constraint property is then used to associate a page component with a particular `JCTabButton`. Page components can be of any component or container.

The following figure illustrates the anatomy of a typical tabbed dialog.

Anatomy of a tabbed dialog

The following code fragment creates a `JCTabManager` container, then adds several tabs and pages as its children:

    package jclass.bwt.examples;
    import jclass.bwt.BWTEnum;
    import jclass.bwt.JCCheckbox;
    import jclass.bwt.JCCheckboxGroup;
    import jclass.bwt.JCContainer;
    import jclass.bwt.JCGridLayout;
    import jclass.bwt.JCItemEvent;
    import jclass.bwt.JCItemListener;
    import jclass.bwt.JCLabel;
    import jclass.bwt.JCTabButton;
    import jclass.bwt.JCTabManager;
    import jclass.bwt.JCTabManagerEvent;
    import jclass.bwt.JCTabManagerListener;
    import jclass.contrib.ContribFrame;
    import jclass.util.JCString;
    import jclass.util.JCUtilConverter;
    import java.awt.*;
    import java.util.Date;
    /**
     * This example creates a JCTabManager which displays some of the other
     * examples.
     */
    public class tabManager extends java.applet.Applet
    implements Runnable, JCTabManagerListener, JCItemListener {
    JCLabel label = new JCLabel();
    JCTabManager tab_manager;
    transient Thread updater;
    // JCItemListener method
    public void itemStateChanged(JCItemEvent ev) {
    	JCCheckboxGroup group =
    		(JCCheckboxGroup) ((Component)ev.getSource()).getParent();
    	if (group.getTitle().equals("Shape"))
    		tab_manager.setTabShape(group.getValue());
    	else if (group.getTitle().equals("Side"))
    		tab_manager.setTabSide(group.getValue());
    }
    /*
     *  JCTabManagerListener methods
     */
    // Sets the page when the Date or Vendor tab is clicked
    public void tabManagerChangeBegin(JCTabManagerEvent ev) {
    	JCTabButton tab = ev.getNextTab();
    	if (tab.getName().equals("Date")) {
    		label.setLabel(""+new Date());
    		start();
    		return;
    	}
    	// Stop date thread if it is running
    	stop();
    	if (tab.getName().equals("Vendor")) {
    		String url = System.getProperty("java.vendor.url");
    		JCString s = JCString.parse(this, "[COLOR=blue][href=" + url + " TARGET=_blank]" + url);
    		label.setLabel(s);
    	}
    }
    public void tabManagerChangeEnd(JCTabManagerEvent ev) {}
    public Insets insets() { return new Insets(5,5,5,5); }
    static String side_labels[] = { "Top", "Bottom" };
    static int side_values[] = { BWTEnum.TOP, BWTEnum.BOTTOM } ;
    static String shape_labels[] = { "Rectangular", "Slanted" };
    static int shape_values[] = { BWTEnum.RECTANGLE, BWTEnum.SLANTED };
    public void init() {
    	// Force tab manager to be same size as applet
    	setLayout(new GridLayout(1,1));
    	tab_manager = new JCTabManager();
    	tab_manager.addTabManagerListener(this);
    	setBackground(Color.lightGray);
    	JCCheckboxGroup sides = JCCheckbox.makeGroup(side_labels, side_values, true);
    	sides.setTitle("Side");
    	sides.addItemListener(this);
    	JCCheckboxGroup shapes = JCCheckbox.makeGroup(shape_labels, shape_values, true);
    	shapes.setTitle("Shape");
    	shapes.addItemListener(this);
    	JCContainer panel = new JCContainer();
    	panel.setInsets(new Insets(0, 20, 0, 20));
    	panel.setLayout(new JCGridLayout(1, BWTEnum.VARIABLE, 10, 10));
    	panel.add(sides);
    	panel.add(shapes);
    	tab_manager.addPage("Tab Styles", panel);
    	labels l = new labels(this);
    	l.init();
    	l.setBackground(Color.yellow);
    	tab_manager.addPage("Labels", l);
    	buttons b = new buttons(this);
    	b.init();
    	tab_manager.addPage("Buttons", b);
    	/*
    	 * Add tabs which share the same page. The page contents will be set
    	 * in the listener method when the tab is clicked.
    	 */
    	label.setFont(new Font("TimesRoman", Font.BOLD, 20));
    	int pos = tab_manager.addPage("Java Vendor", label);
    	tab_manager.getTab(pos).setName("Vendor");
    	pos = tab_manager.addPage("Current Date", label);
    	tab_manager.getTab(pos).setName("Date");
    	add(tab_manager);
    }
    public void start() {
    	if (updater == null) {
    		updater = new Thread(this);
    		updater.start();
    	}
    }
    public void stop() {
    	if (updater != null) {
    		updater.yield();
    		updater.stop();
    	}
    	updater = null;
    }
    /** Writes the current time every second. */
    public void run() {
    	while (true) {
    		try {
    			Thread.sleep(1000);
    		} catch (Exception e) {}
    		if (!Thread.currentThread().isAlive() || updater == null)
    			return;
    		label.setLabel(""+new Date());
    	}
    }
    public static void main(String args[]) {
    	ContribFrame frame = new ContribFrame("TabManager");
    	tabManager s = new tabManager();
    	s.init();
    	frame.add(s);
    	frame.pack();
    	frame.show();
    }
    }

This creates the following tabbed dialog display:

A sample JCTabManager with child JCTabButtons

This application consists of a Tab Manager, with four `JCTabButtons` defined as its children. Each `JCTabButton` has a page associated with it. Each page, in turn, has other BWT components defined as its child; in more complicated real-life applications, additional container components are defined as children of the pages.

To create a multi-level file folder, define another `JCTabManager` as a page component.

This sample code is incorporated into the example file tabManager.class provided with JClass BWT. For information on how to run this program, see the " Example Program " section at the end of this chapter.

## Changing the Active Tab

The `JCTabManager` component provides two methods to control the display of the tab manager and its children:

- `setCurrentTab()` which sets the current tab, and calls `JCTabManagerEvent`
- `setCurrentPage()` sets the current page.

#### Tab Events

`JCTabManager` can be notified when a page has been changed and can be set at run-time; in other words, a number of tabs could share the same page and `JCTabManager` could set the page contents after the user has clicked a tab.

The `JCTabManagerInfo` constructor defines actions to be invoked whenever the value of `TABMANAGER` changes, which can be set either interactively or programmatically. This enables you to control page display.

Each `TABMANAGER` property is passed the following structure:

    public JCTabManagerInfo(Event ev,
    					Component current,
    					Component next)

Each event is called both before and after the page change takes place. reason indicates which event is occurring, and is either `BEGIN` (before page change) or `END` (after page change).

The new page component and its number are specified by the `current_page` and `next_page` variables. These members can be modified, allowing you to control page changes in a `JCTabManager`. The `doit` field provides an easy way to suppress page changes. If `doit` is set to `false` and `stage` is set to `BEGIN`, the page change does not occur.

## Controlling Tab Display

`JCTabManager` enables you to control the following tab display features:

- tab resizing
- tab stretching
- tab shape
- tab color
- tab placement/orientation.

#### Tab Resizing

The `TabResize` property specifies whether all tabs should be resized to the width or height of the largest tab in the same row. If `TabResize` is `true` (default), resizing is performed; if `false`, each tab is only as large as necessary to display its label.

Tab resizing

#### Ta b Stretching

The `TabStretch` property specifies whether all tabs should be stretched if necessary to fill the entire side.

Tab stretching

To ensure that the tabs take up all the available visible space and are of the same size, set both `TabResize` and `TabStretch` to `true`.

#### Tab Shape

The `TabShape` property sets the shape of the tab. There are two available values: `RECTANGLE` (default), or `SLANTED`. The effects of both values are depicted in the following illustration:

The two values of TabShape illustrated

#### Tab Color

The `TabColorPolicy` property sets the color for individual tabs within `JCTabManager`. `TabColorPolicy` does not directly set the color for an individual tab, instead it either reads the color value from the tabbed page, or sets the tab's color to a value defined within the tab manager. The two values for `TabColorPolicy` are `COLOR_PAGE`, which sets the tab's color to the page's color (default), and `COLOR_INHERIT`, which sets the tab's color to the tab manager's color.

#### Tab Placement

The `TabSide` property sets the placement for the displays of tabs within `JCTabManager`. There are two values for `TabSet`: `TOP` and `BOTTOM`. The effects of both values are depicted in the following illustration:

The two values of TabSide illustrated

## Tab Button Properties

The following sections describe how to use the `JCTabButton` component.

### Altering the Tab Button Font

The `CurrentTabFont` property sets the current tab's font (default: bold version of the default font). It can be altered by specifying a different valid Java font name with the property, as in the following code fragment:

    public void init() {
            JCImageCreator im = new JCImageCreator(this, 16, 16);
            im.setColor('X', Color.red);
            im.setColor('o', Color.black);
            im.setColor('.', Color.white);
            siteImage = im.create(site_icon);
            // Force tab manager to be same size as applet
            setLayout(new GridLayout(1,1));
            setBackground(Color.lightGray);
            tab_manager = new JCTabManager();
            tab_manager.setBackground(Color.lightGray);
            tab_manager.addTabManagerListener(this);
            // set the font for the selected Tab.
            Font newFont = new Font("Courier", Font.PLAIN, 16);
            tab_manager.setCurrentTabFont(newFont);
            theFTPPanel = new FTPPanel(this);
            for (int i=0; i<tabName.length; i++) {
                    JCString        name = new JCString();
                    name.add(siteImage);
                    name.add(tabName[i]);
                    tab_manager.setTabPage(i+1, name, theFTPPanel);
            }
            setTextFields(tab_manager.getCurrentTab());
            tab_manager.setTabStretch(true);
            add(tab_manager);
    }

The result of this code can be seen in the following illustration:

Changing Fonts within the Tabs

This example uses a JCString to insert images within the tab buttons. For more information on JCStrings, see .

### Adding an Image to a Tab Button

To specify a image for a `JCTabButton`, specify an object in the `JCTabButton` constructor. The `JCTabButton` constructor can be passed a String, image or JCString.

The following code fragment displays how to add an image file as an object, and a subsequent tab to display a JCString:

    / This example uses a memory image
    // Static Variables
    static String tabName[] = {
            "Guru", "Gonzo", "KLG's ftp site",
    };
    static final String site_icon[] = {
    "   oooooooooo   ",
    "  o..........o  ",
    "  o..XXXXXX..o  ",
    "  o.X......X.o  ",
    "  o.X......X.o  ",
    "  o.X......X.o  ",
    "  o.X......X.o  ",
    "  o.X......X.o  ",
    "  o..XXXXXX..o  ",
    "  o..........o  ",
    "  o....XXXXX.o  ",
    "  o..........o  ",
    "  oooooooooooo  ",
    "   o........o   ",
    "   o........o   ",
    "   oooooooooo   "};
    public void init() {
            JCImageCreator im = new JCImageCreator(this, 16, 16);
            im.setColor('X', Color.red);
            im.setColor('o', Color.black);
            im.setColor('.', Color.white);
            Image siteImage = im.create(site_icon);
            // Force tab manager to be same size as applet
            setLayout(new GridLayout(1,1));
            setBackground(Color.lightGray);
            tab_manager = new JCTabManager();
            tab_manager.setBackground(Color.lightGray);
            tab_manager.addTabManagerListener(this);
            theFTPPanel = new FTPPanel(this);
            for (int i=0; i<tabName.length; i++) {
                    JCString        name = new JCString();
                    name.add(siteImage);
                    name.add(tabName[i]);
                    tab_manager.setTabPage(i+1, name, theFTPPanel);
            }
            setTextFields(tab_manager.getCurrentTab());
            tab_manager.setTabStretch(true);
            add(tab_manager);
    }

The image is constructed within the code and not via a .GIF image file. The results can be seen in the following illustration.

Inserting images into tab buttons

### Text and Pixmap Positioning

Text and images can be aligned within a `JCTabButton` by using the `Alignment` property which has nine possible values: `TOPLEFT`, `TOPCENTER`, `TOPRIGHT, MIDDLELEFT`, `MIDDLECENTER`, `MIDDLERIGHT, BOTTOMLEFT, BOTTOMCENTER,` and `BOTTOMRIGHT`. All nine values are used with text strings in the following code sample whose results can be seen in the following illustration.

Tab Button text and pixmap layouts

The default is `MIDDLECENTER`.

Text and images can also be aligned using JCStrings. This approach is limited to the three values possible with `ALIGN`: `TOP`, `BOTTOM` and `MIDDLE`. The following code fragment shows how to insert JCStrings within tab labels:

    // Using a JCString with alignment information
                    JCString s = JCString.parse(this, "[ALIGN=TOP]"+tabName[i]);
                    tab_manager.setTabPage(i+1, s, theFTPPanel);

### Specifying Tab Button and Page Colors

Each `JCTabButton` component obtains its color specifications from the page component with which it is associated. To specify your own `JCTabButton` colors, change the appropriate color properties (such as `foreground`) after associating a page component with the `JCTabButton`.

The shadow colors for each page component are, in turn, obtained from the `JCTabButton` color specifications.

## Events

A class can be notified before and after a new `JCTabManager` page is displayed by implementing the `JCTabManagerListener` interface and registering itself with the `tabManager` via `addTabManagerListener`, as the following code demonstrates:

    public interface JCTabManagerListener {
            // Invoked before the page is changed. The event's values can be modified via its setValue method.
            public void tabManagerChangeBegin(JCTabManagerEvent e);
            // Invoked after the page is changed. Any changes made to the event are ignored.
            public void tabManagerChangeEnd(JCTabManagerEvent e);
    }
    public class JCTabManagerEvent {
            // Returns the component where the event originated.
            public Object getSource()
            // Returns the event type.
            public int getId()
            // Gets the current page (null at initialization).
            public Component getCurrentPage()
            // Gets the page that will be displayed.
            public Component getNextPage()
            // Gets the current tab (null at initialization).
            public JCTabButton getCurrentTab()
            // Gets the tab that will be displayed.
            public JCTabButton getNextTab()
            // Sets the page that will be displayed.
            public void setNextPage(Component page)
            // Determines whether the page should change.
            public boolean getChangePage()
            // Determines whether the page should change (default: true).
            public void setChangePage(boolean v)
    }

## Property Listing

The following summarizes the properties of `JCTabManager`. Complete reference documentation is available online in standard javadoc format in jclass.bwt.JCTabManager.html.

### jclass.bwt.JCTabManager

Name | Method | Inherited from
--- | --- | ---
`Alignment` | `setAlignment` | `jclass.bwt.JCTabManager`
`Background` | `setBackground` | `jclass.bwt.JCContainer`
`CurrentTabFont` | `setCurrentTabFont` | `jclass.bwt.JCTabManager`
`FirstVisibleTab` | `setFirstVisibleTab` | `jclass.bwt.JCTabManager`
`Font` | `setFont` | `jclass.bwt.JCContainer`
`Foreground` | `setForeground` | `jclass.bwt.JCContainer`
`Insets` | `setInsets` | `jclass.bwt.JCContainer`
`PreferredSize` | `setPreferredSize` | `jclass.bwt.JCContainer`
`TabColorPolicy` | `setTabColorPolicy` | `jclass.bwt.JCTabManager`
`TabResize` | `setTabResize` | `jclass.bwt.JCTabManager`
`TabShape` | `setTabShape` | `class.bwt.JCTabManager`
`TabSpacing` | `setTabSpacing` | `jclass.bwt.JCTabManager`
`TabStretch` | `setTabStretch` | `jclass.bwt.JCTabManager`
`UserData` | `setUserData` | `jclass.bwt.JCContainer`

## Example Program

Demonstration programs and example code containing `JCTabButton`s and `JCTabManager`s come with JClass BWT. The examples can be viewed in applet form by launching index.html within the /jclass/bwt/examples directory. tabManager.class can also be run as a stand-alone Java application from the command prompt by typing:

    	java jclass.bwt.examples.tabManager