3 回答

TA貢獻2039條經(jīng)驗 獲得超8個贊
你很幸運,因為唯一的區(qū)別是顏色。您可以為此目的使用查找顏色:my-color-name: <value>;對節(jié)點本身或祖先之一使用規(guī)則。這允許您指定這些內(nèi)聯(lián) 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條經(jīng)驗 獲得超5個贊
如果您只想更改顏色而不修改 CSS 的其余部分,您也可以遵循以下方法。如果您有一個非常大的 css 文件需要主題化,這會非常有用。
基本思想是讓所有 css 都是一個基本 css 文件。將所有顏色定義為該基本文件中 .root 類中的變量。對于每個主題 css,您只需要覆蓋顏色變量即可。并在基本文件之上加載主題 css 文件。這樣您就不會遇到任何可能的復(fù)制粘貼問題或缺少 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條經(jīng)驗 獲得超7個贊
以下是動態(tài)設(shè)置給定組件主題顏色的幾個具體示例:
費邊對查找顏色的建議。
以編程方式創(chuàng)建的 CSS 樣式表寫入臨時文件。
使用查找顏色的示例
該示例正在做的是設(shè)置一些標(biāo)準(zhǔn)查找顏色,這些顏色可以為modena.css
您想要設(shè)置樣式的三件事設(shè)置樣式:
背景顏色 (?
-fx-background-color
)。這是從該類派生的類中使用的標(biāo)準(zhǔn)背景Pane
。文本的顏色 (?
-fx-text-background-color
)。是的,我知道這個名字很令人困惑,但無論出于什么原因,它似乎就是這樣。按鈕的顏色 (?
-fx-base
)。
在示例應(yīng)用程序中,用戶可以使用 JavaFXColorPicker控件動態(tài)選擇顏色來修改預(yù)覽窗格中顯示的項目的顏色。
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);
? ? }
}
使用動態(tài)樣式表的示例
更新
JavaFX 17 添加了從數(shù)據(jù) URI 加載樣式表的功能。這將是下面示例中演示的另一種方法,該方法使用文件 IO 動態(tài)創(chuàng)建 CSS 文件。
因此,查找顏色解決方案非常強大,因為您可以動態(tài)設(shè)置場景中所有項目的顏色樣式。然而,CSS 一般來說比顏色設(shè)置更強大。如果您的動態(tài)樣式需要的不僅僅是顏色設(shè)置,或者您需要非常具體的規(guī)則來設(shè)置場景中特定項目的樣式,那么您將需要自己的自定義樣式表。
stylesheets節(jié)點和場景的屬性是一個動態(tài)的可觀察列表。因此,如果更改樣式表,您將重新設(shè)置節(jié)點或場景的樣式。每個樣式表都由一個 URL 引用。因此,要動態(tài)創(chuàng)建樣式表,您需要做的就是在代碼中構(gòu)造樣式表內(nèi)容并將其寫入臨時文件,獲取對臨時文件的 URL 引用,然后將其設(shè)置為您想要的樣式表風(fēng)格。
要提供此方法的示例,只需使用上一個示例中使用查找顏色的代碼,并將 setThemeColors 方法替換為以下方法。然后,這將使用動態(tài)創(chuàng)建的 CSS 文件而不是查找的顏色來完成預(yù)覽窗格的動態(tài)樣式。
注意:在創(chuàng)建動態(tài)樣式表時,我嘗試使用選擇.root器來定義樣式(類似于 Sai 的答案),但是,無論出于何種原因,它都不起作用(也許它不適用于我的 JavaFX (v13) 版本) 。因此,我使用特定的 CSS 選擇器來設(shè)置項目的樣式(例如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();
? ? }
}
查找顏色的背景
以下文檔是從有關(guān)查找顏色的鏈接 JavaFX CSS 參考部分復(fù)制的。這是一種實現(xiàn)您愿望的強大技術(shù),并且該概念(據(jù)我所知)是 JavaFX CSS 處理所特有的,并且在基于標(biāo)準(zhǔn) HTML 的 CSS 中不存在。
通過查找顏色,您可以引用在當(dāng)前節(jié)點或其任何父節(jié)點上設(shè)置的任何其他顏色屬性。這是一個非常強大的功能,因為它允許在場景上指定通用顏色調(diào)色板,然后在整個應(yīng)用程序中使用。如果您想更改其中一種調(diào)色板顏色,您可以在場景樹中的任何級別執(zhí)行此操作,這將影響該節(jié)點及其所有后代。查找到的顏色在應(yīng)用之前不會被查找,因此它們是實時的,并對可能發(fā)生的任何樣式更改做出反應(yīng),例如在運行時用節(jié)點上的“樣式”屬性替換調(diào)色板顏色。
如果您在您正在使用的 JavaFX SDK 附帶的 jar 文件中進行搜索,您將找到一個名為modena.css. 該文件預(yù)定義了許多查找的顏色,您可以覆蓋這些顏色,以便更輕松地為應(yīng)用程序設(shè)置主題。這些沒有在任何地方記錄,您需要查看 modena.css 文件以了解它們是什么(最有用的文件位于.root文件的 部分)。最重要的顏色-fx-base將為整個 JavaFX 控制系統(tǒng)設(shè)置基色。
查找的顏色通常與其他一些 JavaFX CSS 概念(例如派生和階梯)結(jié)合起來,以創(chuàng)建一致的主題,當(dāng)基本查找顏色發(fā)生變化時,這些主題仍然可讀。這允許您更改基色,例如從白色更改為黑色,并且基于基色的控件中顯示的文本將自動從回更改為白色,以便仍然可讀。
什么是-fx-base?
fx-base是所有控件的基色,因此設(shè)置它會更改場景中所有控件的顏色,這可能也是您想要的,但也許不是。
如果您只想更改按鈕而不是場景中的所有內(nèi)容,只需直接在每個按鈕上而不是在封閉的窗格上設(shè)置 -fx-base 顏色即可。實現(xiàn)這一目標(biāo)的一種棘手方法是,您可以為按鈕定義自己的 CSS 樣式,然后在程序中將樣式-fx-base: my-custom-color設(shè)置為動態(tài)值,如 fabian 的答案所示。my-custom-color
請注意,設(shè)置基色優(yōu)于嘗試設(shè)置實際按鈕顏色。因為,當(dāng)您仔細(xì)觀察時,按鈕本身包括從基色派生的各種漸變和陰影,因此在渲染時它實際上是由多種顏色組成的,而不僅僅是單一顏色。
添加回答
舉報