CSS поиски по своей природе зависят от деталей реализации инфраструктуры рендеринга, и, как таковые, они могут быть ненадежными, и вам следует по возможности избегать их использования. В частности, поиск не будет работать, если на графе сцены не был сделан проход CSS (как правило, это происходит во время рендеринга), или если с момента последнего прохода CSS произошли изменения в состоянии CSS. Я думаю, что с вашим кодом происходит то, что слушатель вызывается до того, как состояние CSS будет обновлено новым состоянием выбора, в результате чего вы получите неправильный Tab
из поиска .tab:selected
(хотя я нет уверенности, что это именно то, что происходит).
Обратите внимание, что у вас уже есть большая часть необходимого динамического поведения c, поскольку псевдокласс "selected"
будет обновляться динамически.
Лучший Подход к такой функциональности заключается в том, чтобы определить внешний файл CSS, который охватывает все возможные стили, а затем программно изменить состояние CSS, используя один из нескольких механизмов. Для этого есть несколько способов:
- Использовать «искомые цвета». Они действуют как имена переменных в CSS.
- Использование пользовательских псевдоклассов, которые вы можете использовать в качестве селекторов в файле CSS, и состояние которых вы можете обновлять программно.
Вот пример с использованием первого подхода. Здесь мы определяем искомый цвет в файле CSS с именем "selected-tab-color"
, который изначально устанавливает для кнопки закрытия синий цвет.
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 по умолчанию (т. е. имени цвета по умолчанию для кнопки закрытия вкладки).
A немного Лучший способ включить или отключить эту функцию программно - использовать собственный псевдокласс. Они работают как любой другой псевдокласс CSS, и их состояние может быть изменено программно.
В этом примере цвет кнопки закрытия будет красным, только если на вкладке, содержащей вкладку, установлен псевдокласс warn-on-close
:
.tab-pane:warn-on-close .tab:selected > .tab-container > .tab-close-button {
-fx-background-color: red ;
}
А в коде Java здесь мы включаем это, когда выбрана вкладка 2, и выключаем, когда выбираются другие. Опять же, здесь возможна произвольная логика c.
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);
}
}