CSS 查找本质上依赖于渲染框架的实现细节,因此它们可能不可靠,您应该尽可能避免使用它们。特别是,如果尚未在场景图上进行 CSS 传递(通常在渲染期间发生),或者自上次 CSS 传递以来发生了 CSS 状态的更改,则查找将不起作用。我认为您的代码发生的情况是在使用新的选择状态更新 CSS 状态之前调用了侦听器,导致您从 .tab:selected 查找中检索错误的 Tab(尽管我绝不是确定这是正在发生的事情)。
请注意,您已经拥有大部分所需的动态行为,因为"selected" 伪类将动态更新。
实现此类功能的最佳方法是定义一个涵盖所有可能样式的外部 CSS 文件,然后使用多种机制中的一种以编程方式修改 CSS 状态。有几种方法可以做到这一点:
- 使用“查找颜色”。这些就像 CSS 中的变量名一样。
- 使用自定义伪类,您可以将其用作 CSS 文件中的选择器,并且可以通过编程方式更新其状态。
这是使用第一种方法的示例。在这里,我们在名为 "selected-tab-color" 的 CSS 文件中定义了一种查找颜色,它最初将关闭按钮设置为蓝色。
tabpane.css:
.tab-pane {
selected-tab-color: blue ;
}
.tab:selected > .tab-container > .tab-close-button {
-fx-background-color: selected-tab-color ;
}
在 Java 代码中,我们可以简单地通过调用 tabPane.setStyle("selected-tab-color: red;") 来更新它,例如,在事件处理程序中(但实际上是在任何地方,只要它在 JavaFX 应用程序线程上)。在这个例子中,我们只是列出了选中的标签,并让一个标签有一个红色的关闭按钮,其他的都是蓝色的。
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TabPaneTest extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
TabPane tabPane = new TabPane();
Tab tab1 = new Tab("Tab 1", new Label("Tab 1"));
Tab tab2 = new Tab("Tab 2", new Label("This tab has\na custom close button"));
Tab tab3 = new Tab("Tab 3", new Label("Tab 3"));
tabPane.getTabs().addAll(tab1, tab2, tab3);
tabPane.getSelectionModel().selectedItemProperty().addListener((obs, oldTab, newTab) -> {
if (newTab == tab2) {
tabPane.setStyle("selected-tab-color: red;");
} else {
tabPane.setStyle("selected-tab-color: blue;");
}
});
BorderPane root = new BorderPane(tabPane);
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("tabpane.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setWidth(250);
primaryStage.setHeight(250);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
您可以使用此技术完全关闭效果,方法是恢复为默认值:
tabPane.setStyle("selected-tab-color: -fx-mark-color;");
然而,这依赖于了解默认 CSS 实现的细节(即标签关闭按钮的默认颜色名称)。
以编程方式打开或关闭功能的更好方法是使用自定义 Pseudoclass。它们像任何其他 CSS 伪类一样工作,并且可以通过编程方式修改它们的状态。
在本例中,关闭按钮的颜色只有在包含的选项卡窗格设置了 warn-on-close 伪类时才会显示为红色:
.tab-pane:warn-on-close .tab:selected > .tab-container > .tab-close-button {
-fx-background-color: red ;
}
在这里的 Java 代码中,我们在选择选项卡 2 时将其打开,在选择其他选项卡时关闭。同样,这里可以使用任意逻辑。
import javafx.application.Application;
import javafx.css.PseudoClass;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TabPaneTest extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
TabPane tabPane = new TabPane();
Tab tab1 = new Tab("Tab 1", new Label("Tab 1"));
Tab tab2 = new Tab("Tab 2", new Label("This tab has\na custom close button"));
Tab tab3 = new Tab("Tab 3", new Label("Tab 3"));
tabPane.getTabs().addAll(tab1, tab2, tab3);
PseudoClass warnOnClosePseudoClass = PseudoClass.getPseudoClass("warn-on-close");
tabPane.getSelectionModel().selectedItemProperty().addListener((obs, oldTab, newTab) ->
tabPane.pseudoClassStateChanged(warnOnClosePseudoClass, newTab == tab2));
BorderPane root = new BorderPane(tabPane);
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("tabpane.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setWidth(250);
primaryStage.setHeight(250);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}