In modern software development, building user-friendly and organized user interfaces is essential to provide a smooth and efficient user experience. JavaFX, a popular UI toolkit for Java, offers a powerful and versatile component called TabPane, which allows developers to create tabbed interfaces that can easily manage multiple views or functionalities within a single window. In this article, we’ll explore the JavaFX TabPane and demonstrate how to use it effectively with full code examples.
What is TabPane?
A TabPane is a container in JavaFX that provides a tab-based navigation system. It allows the application to present multiple tabs, where each tab can hold its own content or view. Users can switch between different tabs to access various functionalities or information within the same window, improving the organization and usability of the application. The TabPane provides an organized way to present multiple sets of content, making it ideal for scenarios where you need to display various related views without cluttering the main interface.
Creating a Basic TabPane
Let’s start by creating a basic JavaFX application with a TabPane containing two tabs.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class Main extends Application {
private final BorderPane parent = new BorderPane();
@Override
public void start(Stage stage) throws Exception {
this.setupStage(stage);
}
@Override
public void init() throws Exception {
super.init();
this.buildUI();
}
private void buildUI() {
TabPane tabPane = new TabPane();
// Create tabs
Tab tab1 = new Tab("Tab 1");
Tab tab2 = new Tab("Tab 2");
// Add content to tabs
tab1.setContent(new BorderPane(new Label("Content 1")));
tab2.setContent(new BorderPane(new Label("Content 2")));
// Add tabs to the TabPane
tabPane.getTabs().addAll(tab1, tab2);
// Add the TabPane to the BorderPane layout manager
this.parent.setCenter(tabPane);
}
private void setupStage(Stage stage) {
Scene scene = new Scene(this.parent, 640.0, 480.0);
// Set the stage title
stage.setTitle("JavaFX TabPane: Building User-Friendly Tabbed Interfaces");
// Set the stage scene
stage.setScene(scene);
// Center the stage on the screen
stage.centerOnScreen();
// Show the stage on the screen
stage.show();
}
}
Customizing Tabs
You can customize the appearance of the tabs by using CSS or directly setting properties on the Tab instances. Let’s add icons to the tabs in the previous example.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class Main extends Application {
private final BorderPane parent = new BorderPane();
@Override
public void start(Stage stage) throws Exception {
this.setupStage(stage);
}
@Override
public void init() throws Exception {
super.init();
this.buildUI();
}
private void buildUI() {
TabPane tabPane = new TabPane();
// Create tabs with icons,
// Assuming java.png and python.png icons are in the same directory as this Java source file
Tab tab1 = new Tab("Tab 1");
tab1.setGraphic(new ImageView(new Image("java.png")));
Tab tab2 = new Tab("Tab 2");
tab2.setGraphic(new ImageView(new Image("python.png")));
// Add content to tabs
tab1.setContent(new BorderPane(new Label("Content 1")));
tab2.setContent(new BorderPane(new Label("Content 2")));
// Add tabs to the TabPane
tabPane.getTabs().addAll(tab1, tab2);
// Add the TabPane to the BorderPane layout manager
this.parent.setCenter(tabPane);
}
private void setupStage(Stage stage) {
Scene scene = new Scene(this.parent, 640.0, 480.0);
// Set the stage title
stage.setTitle("JavaFX TabPane: Building User-Friendly Tabbed Interfaces");
// Set the stage scene
stage.setScene(scene);
// Center the stage on the screen
stage.centerOnScreen();
// Show the stage on the screen
stage.show();
}
}
Adding Event Handlers
Adding event handlers to the tabs in a JavaFX TabPane allows you to respond to user interactions with the tabs. You can perform actions when a tab is selected, deselected, or closed. Here’s an example of adding a simple event handler to display a message when a tab is selected:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class Main extends Application {
private final BorderPane parent = new BorderPane();
@Override
public void start(Stage stage) throws Exception {
this.setupStage(stage);
}
@Override
public void init() throws Exception {
super.init();
this.buildUI();
}
private void buildUI() {
TabPane tabPane = new TabPane();
// Create tabs with icons,
// Assuming java.png and python.png icons are in the same directory as this Java source file
Tab tab1 = new Tab("Tab 1");
tab1.setGraphic(new ImageView(new Image("java.png")));
Tab tab2 = new Tab("Tab 2");
tab2.setGraphic(new ImageView(new Image("python.png")));
// Event handler for tab selection
tab1.setOnSelectionChanged(event -> {
if (tab1.isSelected()) {
System.out.println("Tab 1 is selected.");
}
});
// Event handler for tab deselection
tab2.setOnSelectionChanged(event -> {
if (!tab2.isSelected()) {
System.out.println("Tab 2 is deselected.");
}
});
// Add content to tabs
tab1.setContent(new BorderPane(new Label("Content 1")));
tab2.setContent(new BorderPane(new Label("Content 2")));
// Add tabs to the TabPane
tabPane.getTabs().addAll(tab1, tab2);
// Add the TabPane to the BorderPane layout manager
this.parent.setCenter(tabPane);
}
private void setupStage(Stage stage) {
Scene scene = new Scene(this.parent, 640.0, 480.0);
// Set the stage title
stage.setTitle("JavaFX TabPane: Building User-Friendly Tabbed Interfaces");
// Set the stage scene
stage.setScene(scene);
// Center the stage on the screen
stage.centerOnScreen();
// Show the stage on the screen
stage.show();
}
}
In this example, we create a TabPane with two tabs: “Tab 1” and “Tab 2”. We then use setOnSelectionChanged method to attach event handlers to each tab.
For “Tab 1”, when it is selected, the event handler is triggered, and and a message is printed to the console,saying “Tab 1 is selected.”
For “Tab 2”, when it is deselected (i.e., another tab is selected), the event handler is triggered, and a message is printed to the console, saying “Tab 2 is deselected.”
You can further customize these event handlers to perform more complex actions, like loading data or updating UI elements specific to each tab. Event handlers give you the flexibility to respond to user interactions in a dynamic and interactive way, making your JavaFX application more user-friendly and intuitive.
Dynamic Tab Creation
In many applications, you might need to create tabs dynamically based on user interactions or data. Here’s an example of how to dynamically add new tabs to the TabPane.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class Main extends Application {
private final BorderPane parent = new BorderPane();
@Override
public void start(Stage stage) throws Exception {
this.setupStage(stage);
}
@Override
public void init() throws Exception {
super.init();
this.buildUI();
}
private void buildUI() {
TabPane tabPane = new TabPane();
Button addButton = new Button("Add Tab");
addButton.setOnAction(event -> {
int tabNumber = tabPane.getTabs().size() + 1;
// Create new Tab
Tab newTab = new Tab("New Tab " + tabNumber);
// Set content for new Tab
newTab.setContent(new BorderPane(new Label("New Content " + tabNumber)));
// Add tab to the TabPane
tabPane.getTabs().add(newTab);
// Select new Tab
tabPane.getSelectionModel().select(newTab);
});
// Add the TabPane to the BorderPane layout manager
this.parent.setCenter(tabPane);
// Add the Button to the BorderPane layout manager
this.parent.setBottom(addButton);
}
private void setupStage(Stage stage) {
Scene scene = new Scene(this.parent, 640.0, 480.0);
// Set the stage title
stage.setTitle("JavaFX TabPane: Building User-Friendly Tabbed Interfaces");
// Set the stage scene
stage.setScene(scene);
// Center the stage on the screen
stage.centerOnScreen();
// Show the stage on the screen
stage.show();
}
}
Handling Tab Closure
Handling tab closure in JavaFX involves listening for the close request event on the Tab itself. By default, JavaFX provides users with the ability to close tabs by clicking on the close button (a small “X” icon) located on each tab. To perform actions when a tab is closed, you can add a listener to the onCloseRequest property of the Tab and handle the event accordingly.
Here’s an example of how to handle tab closure using the onCloseRequest event:
import javafx.application.Application;
import javafx.event.Event;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class Main extends Application {
private final BorderPane parent = new BorderPane();
private final TabPane tabPane = new TabPane();
@Override
public void start(Stage stage) throws Exception {
this.setupStage(stage);
}
@Override
public void init() throws Exception {
super.init();
this.buildUI();
}
private void buildUI() {
// Create tabs
Tab tab1 = new Tab("Tab 1");
Tab tab2 = new Tab("Tab 2");
// Add content to tabs
tab1.setContent(new BorderPane(new Label("Content 1")));
tab2.setContent(new BorderPane(new Label("Content 2")));
// Add tabs to the TabPane
this.tabPane.getTabs().addAll(tab1, tab2);
// Handle tab closure request
this.tabPane.getTabs().forEach(tab -> tab.setOnCloseRequest(this::onTabCloseRequest));
// Add the TabPane to the BorderPane layout manager
this.parent.setCenter(tabPane);
}
private void onTabCloseRequest(Event event) {
Tab tab = (Tab) event.getSource();
event.consume(); // Consume the event to prevent the default tab closure action
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Close Tab");
alert.setHeaderText(null);
alert.setContentText("Do you want to close this tab?");
alert.showAndWait()
.filter(response -> response == ButtonType.OK)
.ifPresent(response -> this.tabPane.getTabs().remove(tab));
}
private void setupStage(Stage stage) {
Scene scene = new Scene(this.parent, 640.0, 480.0);
// Set the stage title
stage.setTitle("JavaFX TabPane: Building User-Friendly Tabbed Interfaces");
// Set the stage scene
stage.setScene(scene);
// Center the stage on the screen
stage.centerOnScreen();
// Show the stage on the screen
stage.show();
}
}
The onCloseRequest event handler displays a confirmation dialog (Alert) when the user tries to close a tab. If the user clicks the “OK” button in the dialog, the tab is removed from the TabPane. The event.consume() call prevents the default tab closure behavior, so the tab will only be closed if the user confirms the action in the dialog.
By implementing this tab closure handling, you can provide users with the option to close tabs while giving them a chance to confirm the action before any data is lost.
TabPane with Different Content
In a real-world application, each tab may contain different content. Here’s an example of a TabPane with various types of content.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class Main extends Application {
private final BorderPane parent = new BorderPane();
@Override
public void start(Stage stage) throws Exception {
this.setupStage(stage);
}
@Override
public void init() throws Exception {
super.init();
this.buildUI();
}
private void buildUI() {
TabPane tabPane = new TabPane();
// Create tabs
Tab tab1 = new Tab("Name");
Tab tab2 = new Tab("Essay");
TextField textField = new TextField();
textField.setMaxWidth(300.0);
textField.setPromptText("Enter Your Name:");
TextArea textArea = new TextArea();
textArea.setPromptText("Type Your Essay Here...");
// Add content to tabs
tab1.setContent(new BorderPane(textField));
tab2.setContent(new BorderPane(textArea));
// Add tabs to the TabPane
tabPane.getTabs().addAll(tab1, tab2);
// Add the TabPane to the BorderPane layout manager
this.parent.setCenter(tabPane);
}
private void setupStage(Stage stage) {
Scene scene = new Scene(this.parent, 640.0, 480.0);
// Set the stage title
stage.setTitle("JavaFX TabPane: Building User-Friendly Tabbed Interfaces");
// Set the stage scene
stage.setScene(scene);
// Center the stage on the screen
stage.centerOnScreen();
// Show the stage on the screen
stage.show();
}
}
Understanding TabClosingPolicy
By default, the TabPane comes with a built-in tab closing functionality that allows users to close individual tabs by clicking on the close button (a small “X” icon) associated with each tab. However, JavaFX also provides the flexibility to customize this behavior using the TabClosingPolicy enumeration. The TabClosingPolicy enumeration in JavaFX represents different policies for handling tab closure in a TabPane. It provides three predefined values:
TabClosingPolicy.SELECTED_TAB
In this mode, users can only close the currently selected tab. Attempting to close other tabs will be ignored. This policy is useful when you want to prevent users from accidentally closing tabs that contain essential content.
TabClosingPolicy.UNAVAILABLE
With this policy, the close buttons are not displayed on any tab, and users cannot close tabs. This option is suitable when you want to disable tab closure functionality entirely.
TabClosingPolicy.ALL_TABS
This is the default behavior, allowing users to close any tab by clicking on the respective close button. Tabs can be closed regardless of which tab is currently selected.
To use the TabClosingPolicy in your JavaFX application, you can set it on the TabPane instance using the setTabClosingPolicy() method. Here’s an example of how to implement the different policies:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class Main extends Application {
private final BorderPane parent = new BorderPane();
@Override
public void start(Stage stage) throws Exception {
this.setupStage(stage);
}
@Override
public void init() throws Exception {
super.init();
this.buildUI();
}
private void buildUI() {
TabPane tabPane = new TabPane();
// Create tabs
Tab tab1 = new Tab("Tab 1");
Tab tab2 = new Tab("Tab 2");
// Add content to tabs
tab1.setContent(new BorderPane(new Label("Content 1")));
tab2.setContent(new BorderPane(new Label("Content 2")));
// Set the tabClosingPolicy to UNAVAILABLE to disable tab closure
tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);
// Set the tabClosingPolicy to SELECTED_TAB to allow closing only the selected tab
// tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.SELECTED_TAB);
// By default, the tabClosingPolicy is set to ALL_TABS, which allows closing any tab
// tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.ALL_TABS);
// Add tabs to the TabPane
tabPane.getTabs().addAll(tab1, tab2);
// Add the TabPane to the BorderPane layout manager
this.parent.setCenter(tabPane);
}
private void setupStage(Stage stage) {
Scene scene = new Scene(this.parent, 640.0, 480.0);
// Set the stage title
stage.setTitle("JavaFX TabPane: Building User-Friendly Tabbed Interfaces");
// Set the stage scene
stage.setScene(scene);
// Center the stage on the screen
stage.centerOnScreen();
// Show the stage on the screen
stage.show();
}
}
In this example, we create a simple TabPane with two sample tabs: “Tab 1” and “Tab 2”. You can uncomment the appropriate line to set the desired TabClosingPolicy and observe the behavior accordingly.
Conclusion
The JavaFX TabPane is a powerful component for organizing content and providing a clean user interface. In this article, we covered the basics of working with the TabPane, including creating a basic TabPane, customizing tabs, adding event handlers, dynamic tab creation, and closing tabs dynamically. By utilizing these features, you can create robust and interactive desktop applications with JavaFX.
I hope you found this code informative and useful. If you would like to receive more content, please consider subscribing to our newsletter!