JavaFX以编程方式更改所选选项卡的关闭按钮背景



我只想更改所选选项卡的关闭图标背景,问题是当有一个选项卡时它可以工作,但当我添加更多时,在关闭第一个选项卡之前什么都不会发生,以下是我所做的:

tabPane.lookup(".tab:selected:top").lookup(".tab-container").lookup(".tab-close-button").setStyle("-fx-background-color: red");

现在的问题是,当我选择另一个选项卡并尝试更改它的颜色时,什么都不会发生,直到我关闭上一个更改的选项卡。

快速示例:
我有两个带有白色关闭按钮的选项卡,
选择选项卡1:颜色变了,
I选择选项卡2:什么都没发生,
1关闭选项卡1,然后选择选项卡2:选项卡2的关闭按钮变了。

选择的选项卡是正确的,因为如果我为每个选项卡打印这2行:

System.out.println(tabPane.getSelectionModel().getSelectedItem());
System.out.println(tabPane.lookup(".tab:selected:top").lookup(".tab-container").lookup(".tab-close-button"));

结果是:

javafx.scene.control.Tab@6d81182e&lt----tab1
TabPaneSkin$TabHeaderSkin$2@7d620380[styleClass=tab关闭按钮]&lt----tab1
//现在我切换到tab2
javafx.scene.control.Tab@416ca04a&lt----tab2
TabPaneSkin$TabHeaderSkin$2@7d620380[styleClass=tab关闭按钮]&lt----这个地址不应该与第一个地址相同。

PS:我不能在CSS中这样做,因为颜色应该动态变化,当我切换选项卡时,行在侦听器内执行。

谢谢你的帮助!

CSS查找本质上依赖于呈现框架的实现细节,因此它们可能不可靠,您应该尽可能避免使用它们。特别是,如果场景图上没有进行CSS传递(通常在渲染期间发生(,或者自上次CSS传递以来CSS状态发生了更改,则查找将不起作用,导致您从.tab:selected查找中检索到错误的Tab(尽管我并不确定这是怎么回事(。

请注意,您已经拥有了所需的大部分动态行为,因为"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 hasna 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 hasna 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);
}
}

最新更新