Functionally, tab panes are similar to card panes in that they show only one of a collection of components at a time. Unlike card panes, tab panes include built-in support for navigating between the components, which are called "tabs". The following example demonstrates the use of the TabPane component:
The WTKX source that produces this example is as follows. The tab pane contains three tabs, each of which are flow panes containing bordered labels at different sizes. Like CardPane, the preferred size of a tab pane is the maximum of the preferred widths and heights of the tabs, plus the size of the area allocated to the tab navigation, and each tab is sized to fill the entire space allocated to the tabs. The tab pane itself is contained in a flow pane so that changes to its preferred size are easily visible.
Note that, like the Form container, TabPane defines attributes that a caller can set to customize the appearance of the tab. TabPane currently defines two attributes: "label" and "icon" (additional attributes may be added in the future to support closeable tabs or other such features). Also note that disabling a tab component also disables its corresponding tab button, preventing the user from navigating to that tab:
<Window title="Tab Panes" maximized="true" xmlns:wtkx="http://pivot.apache.org/wtkx" xmlns="org.apache.pivot.wtk"> <content> <TablePane styles="{padding:8, horizontalSpacing:6}"> <columns> <TablePane.Column width="1*"/> <TablePane.Column/> </columns> <rows> <TablePane.Row height="1*"> <Border styles="{padding:12}"> <content> <BoxPane> <TabPane wtkx:id="tabPane"> <tabs> <BoxPane TabPane.icon="org/apache/pivot/tutorials/bell.png" TabPane.label="Bell" styles="{horizontalAlignment:'center', verticalAlignment:'center'}"> <Border> <content> <Label text="240x180" preferredWidth="240" preferredHeight="180" styles="{horizontalAlignment:'center', verticalAlignment:'center'}"/> </content> </Border> </BoxPane> <BoxPane TabPane.icon="org/apache/pivot/tutorials/clock.png" TabPane.label="Clock" styles="{horizontalAlignment:'center', verticalAlignment:'center'}"> <Border> <content> <Label text="320x240" preferredWidth="320" preferredHeight="240" styles="{horizontalAlignment:'center', verticalAlignment:'center'}"/> </content> </Border> </BoxPane> <BoxPane TabPane.icon="org/apache/pivot/tutorials/house.png" TabPane.label="House" styles="{horizontalAlignment:'center', verticalAlignment:'center'}"> <Border> <content> <Label text="480x360" preferredWidth="480" preferredHeight="360" styles="{horizontalAlignment:'center', verticalAlignment:'center'}"/> </content> </Border> </BoxPane> <BoxPane TabPane.icon="org/apache/pivot/tutorials/star.png" TabPane.label="Star" enabled="false"/> </tabs> <corner> <BoxPane wtkx:id="cornerBoxPane" styles="{horizontalAlignment:'right'}"> <TextInput/> </BoxPane> </corner> </TabPane> </BoxPane> </content> </Border> <Border> <content> <BoxPane orientation="vertical" styles="{padding:4, spacing:6}"> <Checkbox wtkx:id="collapsibleCheckbox" buttonData="Collapsible"/> <Label text="Tab orientation:"/> <RadioButton wtkx:id="horizontalRadioButton" buttonData="Horizontal" selected="true" group="tabOrientation"/> <RadioButton wtkx:id="verticalRadioButton" buttonData="Vertical" group="tabOrientation"/> </BoxPane> </content> </Border> </TablePane.Row> </rows> </TablePane> </content> </Window>
The default tab pane skin provides some styles for customizing the appearance and behavior of the tab pane: "collapsible" and "tabOrientation". The "collapsible" style is a boolean that controls how the tab pane responds to clicks on the tab buttons. When set to true, clicking on the selected tab causes the tab pane to "collapse" such that only the tab buttons remain visible. This is handy in situations where screen real estate is at a premium, or when the content of the tab pane may be only periodically relevant to the user but should still be conveniently accessible. The "tabOrientation" style controls how the buttons themselves are laid out - either horizontally or vertically.
The Java source for this example is as follows. It is fairly simple, consisting mostly of event handling code for the radio buttons and checkbox:
package org.apache.pivot.tutorials.navigation; import org.apache.pivot.collections.Map; import org.apache.pivot.wtk.Application; import org.apache.pivot.wtk.Button; import org.apache.pivot.wtk.ButtonStateListener; import org.apache.pivot.wtk.Checkbox; import org.apache.pivot.wtk.DesktopApplicationContext; import org.apache.pivot.wtk.Display; import org.apache.pivot.wtk.BoxPane; import org.apache.pivot.wtk.Orientation; import org.apache.pivot.wtk.RadioButton; import org.apache.pivot.wtk.TabPane; import org.apache.pivot.wtk.Window; import org.apache.pivot.wtkx.WTKXSerializer; public class TabPanes implements Application { private Window window = null; private TabPane tabPane = null; private Checkbox collapsibleCheckbox = null; private RadioButton horizontalRadioButton = null; private RadioButton verticalRadioButton = null; private BoxPane cornerBoxPane = null; public void startup(Display display, Map<String, String> properties) throws Exception { WTKXSerializer wtkxSerializer = new WTKXSerializer(); window = (Window)wtkxSerializer.readObject(this, "tab_panes.wtkx"); tabPane = (TabPane)wtkxSerializer.get("tabPane"); collapsibleCheckbox = (Checkbox)wtkxSerializer.get("collapsibleCheckbox"); horizontalRadioButton = (RadioButton)wtkxSerializer.get("horizontalRadioButton"); verticalRadioButton = (RadioButton)wtkxSerializer.get("verticalRadioButton"); cornerBoxPane = (BoxPane)wtkxSerializer.get("cornerBoxPane"); ButtonStateListener checkboxStateListener = new ButtonStateListener() { public void stateChanged(Button button, Button.State previousState) { updateTabPane(); } }; collapsibleCheckbox.getButtonStateListeners().add(checkboxStateListener); ButtonStateListener radioButtonStateListener = new ButtonStateListener() { public void stateChanged(Button button, Button.State previousState) { if (button.isSelected()) { updateTabPane(); } } }; horizontalRadioButton.getButtonStateListeners().add(radioButtonStateListener); verticalRadioButton.getButtonStateListeners().add(radioButtonStateListener); updateTabPane(); window.open(display); } public boolean shutdown(boolean optional) { if (window != null) { window.close(); } return false; } public void suspend() { } public void resume() { } private void updateTabPane() { tabPane.getStyles().put("collapsible", collapsibleCheckbox.isSelected()); if (horizontalRadioButton.isSelected()) { tabPane.getStyles().put("tabOrientation", Orientation.HORIZONTAL); if (tabPane.getCorner() == null) { tabPane.setCorner(cornerBoxPane); } } else { tabPane.getStyles().put("tabOrientation", Orientation.VERTICAL); if (tabPane.getCorner() == cornerBoxPane) { tabPane.setCorner(null); } } } public static void main(String[] args) { DesktopApplicationContext.main(TabPanes.class, args); } }
Note that this example also demonstrates the use of the tab pane corner component. For horizontally oriented tabs, this component appears in the upper right corner; for vertical tabs, it appears in the lower left. The corner component in this example is a flow pane containing a text input; it is hidden when the orientation is changed to vertical because the corner component itself is not rotated and would cause the button area to grow horizontally.
Next: Accordions