3 回答

TA貢獻2039條經驗 獲得超8個贊
你很幸運,因為唯一的區別是顏色。您可以為此目的使用查找顏色:my-color-name: <value>;對節點本身或祖先之一使用規則。這允許您指定這些內聯 css 值并在 CSS 樣式表中使用它們:
@Override
public void start(Stage primaryStage) {
HBox hBox = new HBox();
hBox.setMaxHeight(Region.USE_PREF_SIZE);
hBox.getStyleClass().add("box");
StackPane root = new StackPane(hBox);
Stream.of("red", "green", "blue").map(c -> {
Button b = new Button(c);
b.setOnAction(evt -> {
root.setStyle("-my-background:" + c);
});
return b;
}).forEach(hBox.getChildren()::add);
Scene scene = new Scene(root, 500, 500);
scene.getStylesheets().add(getClass().getResource("/path/to/my/style.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
CSS 樣式表
.box {
-fx-background-color: -my-background;
}
您可以通過這種方式指定多種顏色,例如
root.setStyle("-my-color: red; -some-other-color: brown; -color-3: yellow;");

TA貢獻1821條經驗 獲得超5個贊
如果您只想更改顏色而不修改 CSS 的其余部分,您也可以遵循以下方法。如果您有一個非常大的 css 文件需要主題化,這會非常有用。
基本思想是讓所有 css 都是一個基本 css 文件。將所有顏色定義為該基本文件中 .root 類中的變量。對于每個主題 css,您只需要覆蓋顏色變量即可。并在基本文件之上加載主題 css 文件。這樣您就不會遇到任何可能的復制粘貼問題或缺少 css 問題:)
一個完整的工作示例如下:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.stream.Stream;
public class DynamicStyling_Demo extends Application {
@Override
public void start(Stage stage) throws Exception {
VBox root = new VBox();
root.setAlignment(Pos.CENTER);
root.setSpacing(10);
Stream.of("Default", "Type1", "Type2", "Type3").forEach(type -> {
Button button = new Button("Open " + type);
button.setOnAction(e -> {
Stage subStage = buildStage(type);
subStage.initOwner(stage);
if (!type.equalsIgnoreCase("default")) {
subStage.getScene().getStylesheets().add(this.getClass().getResource(type.toLowerCase() + ".css").toExternalForm());
}
subStage.show();
});
root.getChildren().add(button);
});
Scene sc = new Scene(root, 400, 400);
sc.getStylesheets().add(this.getClass().getResource("base.css").toExternalForm());
stage.setScene(sc);
stage.show();
}
private Stage buildStage(String title) {
Label label = new Label("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
label.setWrapText(true);
VBox.setVgrow(label, Priority.ALWAYS);
Button btn = new Button("Sample Button");
VBox pane = new VBox(label, btn);
pane.getStyleClass().add("my-pane");
StackPane subRoot = new StackPane(pane);
subRoot.setPadding(new Insets(10));
Stage subStage = new Stage();
subStage.setTitle(title);
subStage.setScene(new Scene(subRoot, 300, 300));
subStage.getScene().getStylesheets().add(this.getClass().getResource("base.css").toExternalForm());
return subStage;
}
public static void main(String[] args) {
Application.launch(args);
}
}
基本.css:
.root{
-fx-window-border: #444444;
-fx-window-color: #999999;
-fx-window-text: #111111;
-fx-button-color: #555555;
}
.my-pane{
-fx-border-width: 2px;
-fx-border-color: -fx-window-border;
-fx-background-color: -fx-window-color;
-fx-padding: 10px;
-fx-spacing: 10px;
}
.my-pane .label{
-fx-text-fill: -fx-window-text;
-fx-font-size: 16px;
}
.my-pane .button{
-fx-base: -fx-button-color;
}
類型1.css:
.root{
-fx-window-border: red;
-fx-window-color: yellow;
-fx-window-text: brown;
-fx-button-color: pink;
}
類型2.css:
.root{
-fx-window-border: green;
-fx-window-color: lightblue;
-fx-window-text: white;
-fx-button-color: grey;
}
類型3.css:
.root{
-fx-window-border: brown;
-fx-window-color: lightgreen;
-fx-window-text: blue;
-fx-button-color: yellow;
}

TA貢獻1862條經驗 獲得超7個贊
以下是動態設置給定組件主題顏色的幾個具體示例:
費邊對查找顏色的建議。
以編程方式創建的 CSS 樣式表寫入臨時文件。
使用查找顏色的示例
該示例正在做的是設置一些標準查找顏色,這些顏色可以為modena.css
您想要設置樣式的三件事設置樣式:
背景顏色 (?
-fx-background-color
)。這是從該類派生的類中使用的標準背景Pane
。文本的顏色 (?
-fx-text-background-color
)。是的,我知道這個名字很令人困惑,但無論出于什么原因,它似乎就是這樣。按鈕的顏色 (?
-fx-base
)。
在示例應用程序中,用戶可以使用 JavaFXColorPicker控件動態選擇顏色來修改預覽窗格中顯示的項目的顏色。
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class ThemeMaker extends Application {
? ? @Override
? ? public void start(Stage stage) throws Exception {
? ? ? ? Pane previewPane = createPreviewPane();
? ? ? ? Pane controlPane = createControlPane(previewPane);
? ? ? ? Pane layout = new VBox(
? ? ? ? ? ? ? ? 20,
? ? ? ? ? ? ? ? controlPane,
? ? ? ? ? ? ? ? previewPane
? ? ? ? );
? ? ? ? layout.setPadding(new Insets(10));
? ? ? ? stage.setScene(new Scene(layout));
? ? ? ? stage.show();
? ? }
? ? private Pane createControlPane(Pane previewPane) {
? ? ? ? ColorPicker backgroundColorPicker = new ColorPicker(Color.web("#b3ccff"));
? ? ? ? ColorPicker textColorPicker = new ColorPicker(Color.web("#4d804d"));
? ? ? ? ColorPicker controlColorPicker = new ColorPicker(Color.web("#ffe6cc"));
? ? ? ? GridPane controlPane = new GridPane();
? ? ? ? controlPane.setHgap(5);
? ? ? ? controlPane.setVgap(5);
? ? ? ? controlPane.addRow(0, new Label("Background color:"), backgroundColorPicker);
? ? ? ? controlPane.addRow(1, new Label("Text color:"), textColorPicker);
? ? ? ? controlPane.addRow(2, new Label("Control color:"), controlColorPicker);
? ? ? ? backgroundColorPicker.valueProperty().addListener((observable, oldColor, newColor) ->
? ? ? ? ? ? ? ? setThemeColors(previewPane, backgroundColorPicker.getValue(), textColorPicker.getValue(), controlColorPicker.getValue())
? ? ? ? );
? ? ? ? textColorPicker.valueProperty().addListener((observable, oldColor, newColor) ->
? ? ? ? ? ? ? ? setThemeColors(previewPane, backgroundColorPicker.getValue(), textColorPicker.getValue(), controlColorPicker.getValue())
? ? ? ? );
? ? ? ? controlColorPicker.valueProperty().addListener((observable, oldColor, newColor) ->
? ? ? ? ? ? ? ? setThemeColors(previewPane, backgroundColorPicker.getValue(), textColorPicker.getValue(), controlColorPicker.getValue())
? ? ? ? );
? ? ? ? setThemeColors(previewPane, backgroundColorPicker.getValue(), textColorPicker.getValue(), controlColorPicker.getValue());
? ? ? ? return controlPane;
? ? }
? ? private void setThemeColors(Pane previewPane, Color backgroundColor, Color textColor, Color controlColor) {
? ? ? ? previewPane.setStyle(
? ? ? ? ? ? ? ? "-fx-background-color: " + toHexString(backgroundColor) + ";" +
? ? ? ? ? ? ? ? "-fx-text-background-color: " + toHexString(textColor) + ";" +
? ? ? ? ? ? ? ? "-fx-base: " + toHexString(controlColor) + ";"
? ? ? ? );
? ? }
? ? private Pane createPreviewPane() {
? ? ? ? Label label = new Label(
? ? ? ? ? ? ? ? "Lorem ipsum dolor sit amet, consectetur adipiscing elit, " +
? ? ? ? ? ? ? ? ? ? ? ? "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
? ? ? ? label.setWrapText(true);
? ? ? ? Button btn = new Button("Sample Button");
? ? ? ? Pane previewPane = new VBox(10, label, btn);
? ? ? ? previewPane.setPadding(new Insets(5));
? ? ? ? previewPane.setPrefWidth(200);
? ? ? ? return previewPane;
? ? }
? ? // from https://stackoverflow.com/a/56733608/1155209 "How to get hex web String from JavaFX ColorPicker color?"
? ? private String toHexString(Color value) {
? ? ? ? return "#" + (format(value.getRed()) + format(value.getGreen()) + format(value.getBlue()) + format(value.getOpacity()))
? ? ? ? ? ? ? ? .toUpperCase();
? ? }
? ? private String format(double val) {
? ? ? ? String in = Integer.toHexString((int) Math.round(val * 255));
? ? ? ? return in.length() == 1 ? "0" + in : in;
? ? }
? ? public static void main(String[] args) {
? ? ? ? launch(args);
? ? }
}
使用動態樣式表的示例
更新
JavaFX 17 添加了從數據 URI 加載樣式表的功能。這將是下面示例中演示的另一種方法,該方法使用文件 IO 動態創建 CSS 文件。
因此,查找顏色解決方案非常強大,因為您可以動態設置場景中所有項目的顏色樣式。然而,CSS 一般來說比顏色設置更強大。如果您的動態樣式需要的不僅僅是顏色設置,或者您需要非常具體的規則來設置場景中特定項目的樣式,那么您將需要自己的自定義樣式表。
stylesheets節點和場景的屬性是一個動態的可觀察列表。因此,如果更改樣式表,您將重新設置節點或場景的樣式。每個樣式表都由一個 URL 引用。因此,要動態創建樣式表,您需要做的就是在代碼中構造樣式表內容并將其寫入臨時文件,獲取對臨時文件的 URL 引用,然后將其設置為您想要的樣式表風格。
要提供此方法的示例,只需使用上一個示例中使用查找顏色的代碼,并將 setThemeColors 方法替換為以下方法。然后,這將使用動態創建的 CSS 文件而不是查找的顏色來完成預覽窗格的動態樣式。
注意:在創建動態樣式表時,我嘗試使用選擇.root器來定義樣式(類似于 Sai 的答案),但是,無論出于何種原因,它都不起作用(也許它不適用于我的 JavaFX (v13) 版本) 。因此,我使用特定的 CSS 選擇器來設置項目的樣式(例如label{-fx-text-fill:<custom-color>})。這工作得很好,而且作為獎勵,它展示了通過定義自己的樣式表可以獲得的額外控制級別。
private void setThemeColors(Pane previewPane, Color backgroundColor, Color textColor, Color controlColor) {
? ? try {
? ? ? ? Path cssPath = Files.createTempFile("fx-theme-", ".css");
? ? ? ? Files.writeString(
? ? ? ? ? ? ? ? cssPath,
? ? ? ? ? ? ? ? ".themed{-fx-background-color:"+ toHexString(backgroundColor) +";}" +
? ? ? ? ? ? ? ? ".label{-fx-text-fill:"+ toHexString(textColor) +";}" +
? ? ? ? ? ? ? ? ".button{-fx-base:" + toHexString(controlColor) + ";}"
? ? ? ? );
? ? ? ? cssPath.toFile().deleteOnExit();
? ? ? ? System.out.println("Wrote " + cssPath);
? ? ? ? System.out.println("URL " + cssPath.toUri().toURL().toExternalForm());
? ? ? ? previewPane.getStyleClass().setAll("themed");
? ? ? ? previewPane.getStylesheets().setAll(
? ? ? ? ? ? ? ? cssPath.toUri().toURL().toExternalForm()
? ? ? ? );
? ? } catch (IOException e) {
? ? ? ? e.printStackTrace();
? ? }
}
查找顏色的背景
以下文檔是從有關查找顏色的鏈接 JavaFX CSS 參考部分復制的。這是一種實現您愿望的強大技術,并且該概念(據我所知)是 JavaFX CSS 處理所特有的,并且在基于標準 HTML 的 CSS 中不存在。
通過查找顏色,您可以引用在當前節點或其任何父節點上設置的任何其他顏色屬性。這是一個非常強大的功能,因為它允許在場景上指定通用顏色調色板,然后在整個應用程序中使用。如果您想更改其中一種調色板顏色,您可以在場景樹中的任何級別執行此操作,這將影響該節點及其所有后代。查找到的顏色在應用之前不會被查找,因此它們是實時的,并對可能發生的任何樣式更改做出反應,例如在運行時用節點上的“樣式”屬性替換調色板顏色。
如果您在您正在使用的 JavaFX SDK 附帶的 jar 文件中進行搜索,您將找到一個名為modena.css. 該文件預定義了許多查找的顏色,您可以覆蓋這些顏色,以便更輕松地為應用程序設置主題。這些沒有在任何地方記錄,您需要查看 modena.css 文件以了解它們是什么(最有用的文件位于.root文件的 部分)。最重要的顏色-fx-base將為整個 JavaFX 控制系統設置基色。
查找的顏色通常與其他一些 JavaFX CSS 概念(例如派生和階梯)結合起來,以創建一致的主題,當基本查找顏色發生變化時,這些主題仍然可讀。這允許您更改基色,例如從白色更改為黑色,并且基于基色的控件中顯示的文本將自動從回更改為白色,以便仍然可讀。
什么是-fx-base?
fx-base是所有控件的基色,因此設置它會更改場景中所有控件的顏色,這可能也是您想要的,但也許不是。
如果您只想更改按鈕而不是場景中的所有內容,只需直接在每個按鈕上而不是在封閉的窗格上設置 -fx-base 顏色即可。實現這一目標的一種棘手方法是,您可以為按鈕定義自己的 CSS 樣式,然后在程序中將樣式-fx-base: my-custom-color設置為動態值,如 fabian 的答案所示。my-custom-color
請注意,設置基色優于嘗試設置實際按鈕顏色。因為,當您仔細觀察時,按鈕本身包括從基色派生的各種漸變和陰影,因此在渲染時它實際上是由多種顏色組成的,而不僅僅是單一顏色。
添加回答
舉報