Reputation: 241
Here is a code:
package tabpane;
import javafx.application.*;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.*;
public class HideShowTabContentOnClicked extends Application {
public static void main(String[] args) {
launch(args);
}
private BorderPane createContent() {
BorderPane borderPane = new BorderPane();
TabPane tabPane = new TabPane();
tabPane.setSide(Side.LEFT);
StackPane stackPane = new StackPane();
stackPane.setStyle("-fx-background-color: lightblue");
stackPane.setMinWidth(200);
Tab firstTab = new Tab("First");
firstTab.setClosable(false);
firstTab.setContent(stackPane);
firstTab.selectedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
firstTab.setContent(null);
} else {
firstTab.setContent(stackPane);
}
});
Tab secondTab = new Tab("Second");
StackPane stackPane2 = new StackPane();
stackPane2.setStyle("-fx-background-color: yellow");
secondTab.setContent(stackPane2);
secondTab.setClosable(false);
secondTab.selectedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
secondTab.setContent(null);
} else {
secondTab.setContent(stackPane2);
}
});
StackPane center = new StackPane();
center.setStyle("-fx-background-color: cyan");
borderPane.setCenter(center);
tabPane.getTabs().addAll(firstTab, secondTab);
borderPane.setLeft(tabPane);
return borderPane;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setMaximized(true);
stage.show();
}
}
Here I tried to solve a problem by using selectedProperty() by setting content to null, but it doesn't working, I want to make Tab like toggle button so that when I click on it showed and hide TabPanes content.
Before
And when clicked
As an example I want to implement TabPane like Intellij IDEA Tool Buttons (like "Project", "Structure" Tool Buttons etc).
Upvotes: 4
Views: 1500
Reputation: 141
I have came up with this solution:
AtomicReference<Tab> currentTab = new AtomicReference<>(tabPane.getSelectionModel().getSelectedItem());
AtomicReference<Tab> lastTab = new AtomicReference<>(null);
tabPane.setOnMouseReleased(event -> {
// Check if current node is actually tab
Node n = event.getPickResult().getIntersectedNode();
while (n != null && !(n.getStyleClass().contains("headers-region"))) {
n = n.getParent();
}
if (n == null)
return;
lastTab.set(currentTab.get());
currentTab.set(tabPane.getSelectionModel().getSelectedItem());
if (currentTab.get() == lastTab.get()) {
// Hide
tabPane.setPrefSize(28, 28);
//tabPane.getSelectionModel().clearSelection(); // notify selection model
currentTab.set(null);
} else {
// Show
tabPane.setPrefSize(-1,-1);
currentTab.set(tabPane.getSelectionModel().getSelectedItem());
}
});
First of all, I have added mouse event to the tabPane. Inside this mouse event, check if node under cursor is actually Tab node. If it is, do some logic to identify what user is trying to do: hide or show. Hiding is a bit tricky, so I ended up with setting preferred size of TabPane to 28 px wide.
I have also tried to notify selection model with an empty newValue:
tabPane.getSelectionModel().clearSelection();
But this it is not working properly. Calling select(-1)
should call clearSelection()
, but behavior is different somehow.
When I select another tab after calling clearSelection()
, selection model handler called with oldValue == null
, that possibly does not update internal index and tab does not swithes to selected one.
Upvotes: 0
Reputation: 4471
If you are going to keep your content into StackPane
, you can bind stackPane.visibleProperty()
with toggleButton.selectedProperty()
:
stackPane.visibleProperty()
.bind(Bindings.when(toggleButton.selectedProperty())
.then(false)
.otherwise(true)
);
in this exampl: toggleButton.isSelected() --> !stackPane.isVisible()
and !toggleButton.isSelected() --> stackPane.isVisible()
,
or listen ToggleButton's events
:
// toggleButton.setOnAction(e ->{ //new .setOnAction() -> Override previous
toggleButton.addEventHandler(ActionEvent.ACTION, e ->{ //can add any quantity for your needs
if(toggleButton.isSelected())
stackPane.setVisible(false);
else stackPane.setVisible(true);
});
But the problem is instead of toggle button I want to use Tab, so that it behaves like toggle button. i.e. when click "First Tab" in my example code if content visible it should be invisible and vice versa. I mean only tabs should be shown
I found solution.Tab
does not have click-handler
... but
Tab tab = new Tab();
tab.setContent(stackPane);
Label lable = new Label("Label"); //create Label
tab.setGraphic(lable); //set Lable as Graphic to Tab
lable.setOnMouseClicked(event ->{ //setOnMouseClicked, for example
if(stackPane.isVisible()){
stackPane.setVisible(false);
}else{
stackPane.setVisible(true);
}
});
, you can use Label
(for example) as Tab
-text and add setOnMouseClicked()
-handler to Label
. You can use any Node
with Handler/ActionListener
-> It's up to you.
For example, you can use CheckBox
to show/hide StackPane
, and Tab
text (you can combine FXML
and Java
-code to produce graphics):
Tab tab = new Tab("Tab2"); //Tab with Text
tab.setContent(stackPane);
CheckBox checkBox = new CheckBox(); //create CheckBox
tab.setGraphic(checkBox); //set CheckBox as Graphic to Tab
stackPane.visibleProperty()
.bind(Bindings.when(checkBox.selectedProperty())
.then(false)
.otherwise(true)
);
or
@FXML
private Tab tab;
// ...
tab.setGraphic(checkBox);
// ...
Upvotes: 1