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 BXML 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:
<navigation:TabPanes title="Tab Panes" maximized="true" xmlns:bxml="http://pivot.apache.org/bxml" xmlns:content="org.apache.pivot.wtk.content" xmlns:navigation="org.apache.pivot.tutorials.navigation" xmlns="org.apache.pivot.wtk"> <bxml:define> <Prompt bxml:id="confirmCloseTabPrompt" title="Confirm Close Tab" message="Really close this tab?" options="['Cancel', 'OK']" selectedOptionIndex="1"/> </bxml:define> <TablePane styles="{padding:8, horizontalSpacing:6}"> <columns> <TablePane.Column width="1*"/> <TablePane.Column/> </columns> <TablePane.Row height="1*"> <Border styles="{padding:12}"> <BoxPane> <TabPane bxml:id="tabPane"> <corner> <BoxPane bxml:id="cornerBoxPane" styles="{horizontalAlignment:'right'}"> <TextInput textSize="10"/> </BoxPane> </corner> <BoxPane styles="{horizontalAlignment:'center', verticalAlignment:'center'}"> <TabPane.tabData> <content:ButtonData icon="/org/apache/pivot/tutorials/bell.png" text="Bell"/> </TabPane.tabData> <Border styles="{padding:2}"> <Label text="240x180" preferredWidth="240" preferredHeight="180" styles="{horizontalAlignment:'center', verticalAlignment:'center'}"/> </Border> </BoxPane> <BoxPane styles="{horizontalAlignment:'center', verticalAlignment:'center'}"> <TabPane.tabData> <content:ButtonData icon="/org/apache/pivot/tutorials/clock.png" text="Clock"/> </TabPane.tabData> <Border styles="{padding:2}"> <Label text="320x240" preferredWidth="320" preferredHeight="240" styles="{horizontalAlignment:'center', verticalAlignment:'center'}"/> </Border> </BoxPane> <BoxPane styles="{horizontalAlignment:'center', verticalAlignment:'center'}"> <TabPane.tabData> <content:ButtonData icon="/org/apache/pivot/tutorials/house.png" text="House"/> </TabPane.tabData> <Border styles="{padding:2}"> <Label text="480x360" preferredWidth="480" preferredHeight="360" styles="{horizontalAlignment:'center', verticalAlignment:'center'}"/> </Border> </BoxPane> <BoxPane enabled="false"> <TabPane.tabData> <content:ButtonData icon="/org/apache/pivot/tutorials/star.png" text="Star"/> </TabPane.tabData> <Border styles="{padding:2}"> <Label text="480x360 (disabled)" preferredWidth="480" preferredHeight="360" styles="{horizontalAlignment:'center', verticalAlignment:'center'}"/> </Border> </BoxPane> </TabPane> </BoxPane> </Border> <Border styles="{padding:2}"> <BoxPane orientation="vertical" styles="{padding:4, spacing:6}"> <Checkbox bxml:id="closeableCheckbox" buttonData="Closeable"/> <Checkbox bxml:id="collapsibleCheckbox" buttonData="Collapsible"/> <Label text="Tab orientation:"/> <bxml:define> <ButtonGroup bxml:id="tabOrientation"/> </bxml:define> <RadioButton bxml:id="horizontalRadioButton" buttonData="Horizontal" selected="true" buttonGroup="$tabOrientation"/> <RadioButton bxml:id="verticalRadioButton" buttonData="Vertical" buttonGroup="$tabOrientation"/> </BoxPane> </Border> </TablePane.Row> </TablePane> </navigation:TabPanes>
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 java.net.URL; import org.apache.pivot.beans.Bindable; import org.apache.pivot.collections.Map; import org.apache.pivot.util.Resources; import org.apache.pivot.util.Vote; import org.apache.pivot.wtk.Button; import org.apache.pivot.wtk.ButtonStateListener; import org.apache.pivot.wtk.Checkbox; import org.apache.pivot.wtk.BoxPane; import org.apache.pivot.wtk.Orientation; import org.apache.pivot.wtk.Prompt; import org.apache.pivot.wtk.RadioButton; import org.apache.pivot.wtk.Sheet; import org.apache.pivot.wtk.SheetCloseListener; import org.apache.pivot.wtk.Style; import org.apache.pivot.wtk.TabPane; import org.apache.pivot.wtk.TabPaneListener; import org.apache.pivot.wtk.Window; public class TabPanes extends Window implements Bindable { private Prompt confirmCloseTabPrompt = null; private TabPane tabPane = null; private Checkbox closeableCheckbox = null; private Checkbox collapsibleCheckbox = null; private RadioButton horizontalRadioButton = null; private RadioButton verticalRadioButton = null; private BoxPane cornerBoxPane = null; private boolean confirmCloseTab = true; @Override public void initialize(Map<String, Object> namespace, URL location, Resources resources) { confirmCloseTabPrompt = (Prompt)namespace.get("confirmCloseTabPrompt"); tabPane = (TabPane)namespace.get("tabPane"); closeableCheckbox = (Checkbox)namespace.get("closeableCheckbox"); collapsibleCheckbox = (Checkbox)namespace.get("collapsibleCheckbox"); horizontalRadioButton = (RadioButton)namespace.get("horizontalRadioButton"); verticalRadioButton = (RadioButton)namespace.get("verticalRadioButton"); cornerBoxPane = (BoxPane)namespace.get("cornerBoxPane"); tabPane.getTabPaneListeners().add(new TabPaneListener.Adapter() { @Override public Vote previewRemoveTabs(final TabPane tabPane, final int index, final int count) { Vote vote; if (confirmCloseTab) { confirmCloseTabPrompt.open(TabPanes.this, new SheetCloseListener() { @Override public void sheetClosed(Sheet sheet) { if (confirmCloseTabPrompt.getResult() && confirmCloseTabPrompt.getSelectedOptionIndex() == 1) { confirmCloseTab = false; int n = tabPane.getTabs().getLength(); if (index < n - 1) { tabPane.setSelectedIndex(index + 1); } else { tabPane.setSelectedIndex(index - 1); } tabPane.getTabs().remove(index, count); confirmCloseTab = true; } } }); vote = Vote.DENY; } else { vote = Vote.APPROVE; } return vote; } }); ButtonStateListener checkboxStateListener = new ButtonStateListener() { @Override public void stateChanged(Button button, Button.State previousState) { updateTabPane(); } }; closeableCheckbox.getButtonStateListeners().add(checkboxStateListener); collapsibleCheckbox.getButtonStateListeners().add(checkboxStateListener); ButtonStateListener radioButtonStateListener = new ButtonStateListener() { @Override public void stateChanged(Button button, Button.State previousState) { if (button.isSelected()) { updateTabPane(); } } }; horizontalRadioButton.getButtonStateListeners().add(radioButtonStateListener); verticalRadioButton.getButtonStateListeners().add(radioButtonStateListener); updateTabPane(); } private void updateTabPane() { tabPane.setCloseable(closeableCheckbox.isSelected()); tabPane.setCollapsible(collapsibleCheckbox.isSelected()); if (horizontalRadioButton.isSelected()) { tabPane.getStyles().put(Style.tabOrientation, Orientation.HORIZONTAL); if (tabPane.getCorner() == null) { tabPane.setCorner(cornerBoxPane); } } else { tabPane.getStyles().put(Style.tabOrientation, Orientation.VERTICAL); if (tabPane.getCorner() == cornerBoxPane) { tabPane.setCorner(null); } } } }
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