Peter Penzov
Peter Penzov

Reputation: 1668

Display label if TabPane has no tabs

I want to display label is empty at the center:

private TabPane tabPane = new TabPane();
private Text placeHolder = new Text("Empty");
placeHolder.setFont(Font.font(null, FontWeight.BOLD, 20));
placeHolder.visibleProperty().bind(Bindings.isEmpty(tabPane.getChildren()));

What is the proper way to implement this?

Upvotes: 1

Views: 1095

Answers (1)

Uluk Biy
Uluk Biy

Reputation: 49185

TabPane does not have a ready-to-use placeholder like a TableView does. You may try 3 different approaches:

1) Using custom skin, and set it via -fx-skin.

package my.skin;

import com.sun.javafx.scene.control.skin.TabPaneSkin;

import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.TabPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;


public class CustomTabPaneSkin extends TabPaneSkin
{

    private final VBox placeHolder;
    private final Label placeHolderText;


    public CustomTabPaneSkin( TabPane tabPane )
    {
        super( tabPane );

        placeHolderText = new Label( "Empty" );
        placeHolderText.setFont( Font.font( null, FontWeight.BOLD, 20 ) );
        placeHolderText.setAlignment( Pos.CENTER );

        placeHolderText.minWidthProperty().bind( getSkinnable().widthProperty() );
        placeHolderText.minHeightProperty().bind( getSkinnable().heightProperty() );

        placeHolder = new VBox( placeHolderText );

        for ( Node node : getChildren() )
        {
            if ( node.getStyleClass().contains( "tab-header-area" ) )
            {
                Pane headerArea = ( Pane ) node;
                // Header area is hidden if there is no tabs, thus when the tabpane is "empty"
                headerArea.visibleProperty().addListener( ( observable, oldValue, newValue )
                        -> 
                        {
                            if ( newValue )
                            {
                                getChildren().remove( placeHolder );
                            }
                            else
                            {
                                getChildren().add( placeHolder );
                            }
                        }
                );

                break;
            }
        }
    }

}

and in custom css file

.tab-pane {
  -fx-skin: "my.skin.CustomTabPaneSkin";
}

That's all. Use tabpanes as in usual way.

2) Using custom wrapper that holds tabpane and placeholder

@Override
public void start( Stage primaryStage )
{
    TabPaneHolder tabPaneHolder = new TabPaneHolder( new Tab( "tab 1" ) );
    tabPaneHolder.getTabs().add( new Tab( "tab 2" ) );

    Scene scene = new Scene( tabPaneHolder, 350, 200 );
    primaryStage.setScene( scene );
    primaryStage.show();
}

public class TabPaneHolder extends VBox
{
    private final TabPane tabPane;
    private final Text placeHolder;

    public TabPaneHolder( Tab... tabs )
    {
        this( "Empty", tabs );
    }

    public TabPaneHolder( String emptyMessage, Tab... tabs )
    {
        this.tabPane = new TabPane( tabs );
        placeHolder = new Text( emptyMessage );
        placeHolder.setFont( Font.font( null, FontWeight.BOLD, 20 ) );
        BooleanBinding bb = Bindings.isEmpty( tabPane.getTabs() );
        placeHolder.visibleProperty().bind( bb );
        placeHolder.managedProperty().bind( bb );
        getChildren().addAll( placeHolder, tabPane );

        alignmentProperty().bind( Bindings.when( bb ).then( Pos.CENTER ).otherwise( Pos.TOP_LEFT ) );
    }

    public ObservableList<Tab> getTabs()
    {
        return tabPane.getTabs();
    }
}

3) Simple, direct approach

@Override
public void start( Stage primaryStage )
{
    TabPane tabPane = new TabPane();
    tabPane.getTabs().add( new Tab( "tab" ) );
    Text placeHolder = new Text( "Empty" );
    placeHolder.setFont( Font.font( null, FontWeight.BOLD, 20 ) );
    BooleanBinding bb = Bindings.isEmpty( tabPane.getTabs() );
    placeHolder.visibleProperty().bind( bb );
    placeHolder.managedProperty().bind( bb );

    Scene scene = new Scene( new VBox( placeHolder, tabPane ), 350, 200 );
    primaryStage.setScene( scene );
    primaryStage.show();
}

Upvotes: 5

Related Questions