简体   繁体   English

如何隐藏在 JavaFX 中单击的 Tab 上的 TabPane 内容

[英]How to hide TabPane content on Tab clicked in JavaFX

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.在这里,我尝试通过将 content 设置为 null 来使用 selectedProperty() 解决问题,但它不起作用,我想让 Tab 像切换按钮一样,以便当我单击它时显示并隐藏 TabPanes 内容。

Before之前

And when clicked当点击

As an example I want to implement TabPane like Intellij IDEA Tool Buttons (like "Project", "Structure" Tool Buttons etc).例如,我想实现像 Intellij IDEA 工具按钮(如“项目”、“结构”工具按钮等)的 TabPane。

If you are going to keep your content into StackPane , you can bind stackPane.visibleProperty() with toggleButton.selectedProperty() :如果您要将内容保存在StackPane ,您可以将stackPane.visibleProperty()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.isSelected() --> !stackPane.isVisible()!toggleButton.isSelected() --> stackPane.isVisible() ,或者监听 ToggleButton 的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.但问题是我想使用 Tab 而不是切换按钮,因此它的行为类似于切换按钮。 ie 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没有click-handler ……但是

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 . ,您可以使用Label (例如)作为Tab setOnMouseClicked()并将setOnMouseClicked() -handler 添加到Label You can use any Node with Handler/ActionListener -> It's up to you.您可以将任何NodeHandler/ActionListener ->由您决定。

For example, you can use CheckBox to show/hide StackPane , and Tab text (you can combine FXML and Java -code to produce graphics):例如,您可以使用CheckBox来显示/隐藏StackPaneTab文本(您可以结合FXMLJava代码来生成图形):

在此处输入图片说明

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); 
// ...

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.首先,我在 tabPane 中添加了鼠标事件。 Inside this mouse event, check if node under cursor is actually Tab node.在此鼠标事件中,检查光标下的节点是否实际上是 Tab 节点。 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.隐藏有点棘手,所以我最终将 TabPane 的首选大小设置为 28 px 宽。

I have also tried to notify selection model with an empty newValue:我还尝试用空的 newValue 通知选择模型:

tabPane.getSelectionModel().clearSelection();

But this it is not working properly.但这不能正常工作。 Calling select(-1) should call clearSelection() , but behavior is different somehow.调用select(-1)应该调用clearSelection() ,但行为在某种程度上有所不同。

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.当我在调用clearSelection()后选择另一个选项卡时,选择模型处理程序使用oldValue == null调用,这可能不会更新内部索引并且选项卡不会切换到选定的选项卡。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM