亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

JavaFX:使用 CSS 動態著色窗口

JavaFX:使用 CSS 動態著色窗口

撒科打諢 2023-08-23 17:15:56
我正在嘗試使用 JavaFX 創建一個具有三種不同顏色的 Pane 對象:背景顏色、文本顏色和按鈕顏色。這三種顏色中的每一種都是在運行時根據傳遞到該方法的自定義對象的值動態確定的。我相當輕松地弄清楚了如何直接在我的代碼中實現此行為,并且似乎我可以利用控制器和初始化方法來使用 FXML 進行設置。但我想知道是否可能或建議使用 CSS 設置類似的內容。據我所知,CSS 并沒有真正使用代碼中的變量,只是預先設置的硬編碼值??紤]到潛在組合的數量之多,為每種組合制作不同的紙張似乎沒有多大價值。不過,我聽說使用 CSS 是現代實踐,所以我想知道是否可以使用單個工作表來制作多個不同類型的窗格,或者是否每個可能的窗格都必須使用自己的工作表進行唯一定義,甚至窗格的其他所有內容都是相同的。
查看完整描述

3 回答

?
largeQ

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;");


查看完整回答
反對 回復 2023-08-23
?
收到一只叮咚

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;

}

https://img1.sycdn.imooc.com//64e5ce7f000130c506510469.jpg

查看完整回答
反對 回復 2023-08-23
?
牧羊人nacy

TA貢獻1862條經驗 獲得超7個贊

以下是動態設置給定組件主題顏色的幾個具體示例:

  1. 費邊對查找顏色的建議。

  2. 以編程方式創建的 CSS 樣式表寫入臨時文件。

使用查找顏色的示例

該示例正在做的是設置一些標準查找顏色,這些顏色可以為modena.css您想要設置樣式的三件事設置樣式:

  1. 背景顏色 (?-fx-background-color)。這是從該類派生的類中使用的標準背景Pane。

  2. 文本的顏色 (?-fx-text-background-color)。是的,我知道這個名字很令人困惑,但無論出于什么原因,它似乎就是這樣。

  3. 按鈕的顏色 (?-fx-base)。

https://img1.sycdn.imooc.com/64e5ce8b0001860a02810270.jpg

在示例應用程序中,用戶可以使用 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


請注意,設置基色優于嘗試設置實際按鈕顏色。因為,當您仔細觀察時,按鈕本身包括從基色派生的各種漸變和陰影,因此在渲染時它實際上是由多種顏色組成的,而不僅僅是單一顏色。


查看完整回答
反對 回復 2023-08-23
  • 3 回答
  • 0 關注
  • 287 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號