【问题标题】:How to change the style of components by their attributes?如何通过属性改变组件的样式?
【发布时间】:2019-08-18 23:47:33
【问题描述】:

我想在 javafx 中显示不同的标签,并且我想根据它们的文本设置它们的样式。我添加了一个 css 文件并设置了标签的类。然后我检查了fxml,发现文本保存在text属性中。

我查看了普通的 css,发现您可以通过属性更改样式。为此,您需要使用 []。我在我的代码中尝试了这个,它没有工作。

我的代码: FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.net.URL?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>

<HBox xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1"
      fx:controller="controller">
    <stylesheets>
        <URL value="@../css/loadingScreen.css"/>
    </stylesheets>
    <Label styleClass="field" text="1" />
    <Label styleClass="field" text="2" />
    <Label styleClass="field" text="3" />
</HBox>

CSS:

.field {
    -fx-text-alignment: center;
    -fx-pref-height: 64px;
    -fx-min-width: 64px;
    -fx-pref-width: 64px;
    -fx-min-height: 64px;
    -fx-background-color: blue;
}

.field[text="1"]{
    -fx-background-color: red;
}

.field[text="2"]{
    -fx-background-color: yellow;
}

.field[text="3"]{
    -fx-background-color: green;
}

我用普通的 css 和 html 尝试了同样的方法,它在那里工作。 HTML:

<!DOCTYPE html>
<html>
<head>
<style>
.field[text="1"]{
    background-color: red;
}

.field[text="2"]{
    background-color: yellow;
}

.field[text="3"]{
    background-color: green;
}
</style>
</head>
<body>

<div class="field" text="1" >1</div>
<div class="field" text="2" >2</div>
<div class="field" text="3" >3</div>

</body>
</html>

我必须做什么才能在 fxml 中进行这项工作?

【问题讨论】:

  • 不要相信 JavaFX-CSS 支持你想要的。为什么不根据文字给每个Label 一个一定的style class?或者,如果您只有大约三个标签,每个标签的样式都独一无二,您可以改为设置 their ID
  • 感谢答案,我可能会为每个文本值使用一种样式。我想按属性设置样式的最初原因是,如果我要更改文本,它也会自动更改样式而无需更改类。
  • Slaw 是对的,请参阅 CSS Regerence Guide 的这一部分,从列表开始:openjfx.io/javadoc/11/javafx.graphics/javafx/scene/doc-files/… 现在你似乎没有更新 Labels 所以我不确定你为什么不更新t 简单地使用 ids/style 类在 CSS 中“告诉Labels appart”...

标签: java css javafx pseudo-class


【解决方案1】:

如果我要更改文本,它也会自动更改 风格

选项 1: 按 id 控制样式
您可以通过使用在更改文本时更改样式的自定义标签来实现它。我将通过更改标签的 ID 来演示它。这个简化的示例使用文本作为 id:

import javafx.geometry.Pos;
import javafx.scene.control.Label;

public class CustomLabel extends Label{

    public CustomLabel() {
        setAlignment(Pos.CENTER);
        setPrefSize(50, 25);
    }

    void setTextAndId(String s){
        super.setText(s);
        /*To keep this demo simple and clear id is changed.
          If used, care must be taken to keep id unique. 
          Using setStyle() or PseudoClass should be preferred 
        */
        setId(s); 
    }
}

自定义标签可用于 fxml (Root.fxml):

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.StackPane?>
<?import tests.CustomLabel?>

<StackPane fx:id="root" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" 
fx:controller="tests.Controller">
   <children>
      <CustomLabel fx:id="cLabel" text="&quot;&quot;" />
   </children>
</StackPane>

一个根据 id (Root.css) 改变背景颜色的简单 css:

#1{
    -fx-background-color: red;
    -fx-text-fill: white;
}
#2{
    -fx-background-color: yellow;
    -fx-text-fill: red;
}
#3{
    -fx-background-color: green;
    -fx-text-fill: yellow;
}

测试类:

import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class LabelCssTest extends Application {

    @Override public void start(Stage stage) throws IOException {
        Parent root = FXMLLoader.load(getClass().getResource("Root.fxml"));
        stage.setScene(new Scene(root));
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

和测试控制器:

import javafx.animation.PauseTransition;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.util.Duration;

public class Controller {

    @FXML
    CustomLabel cLabel;
    @FXML Parent root;
    private static final int MIN_VALUE = 1, MAX_VALUE = 3;
    private int counter = MIN_VALUE;

    @FXML
    private void initialize() {

        root.getStylesheets().add(getClass().getResource("Root.css").toExternalForm());
        cLabel.setTextAndId(String.valueOf(counter++));

        PauseTransition pause = new PauseTransition(Duration.seconds(2));
        pause.setOnFinished(event ->{
            cLabel.setTextAndId(String.valueOf(counter++));
            if(counter > MAX_VALUE) {
                counter = MIN_VALUE;
            }
            pause.play();
        });
        pause.play();
    }
}

选项 2: 通过更改样式类控制样式
使用与选项 1 相同的测试类。

Root.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.StackPane?>

<StackPane fx:id="root" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="tests.Controller">
   <children>
      <Label fx:id="label" alignment="CENTER" contentDisplay="CENTER" prefHeight="20.0" prefWidth="70.0" text="&quot; &quot;" />
   </children>
</StackPane>

Root.css

.style1{
    -fx-background-color: red;
    -fx-text-fill: white;
}
.style2{
    -fx-background-color: yellow;
    -fx-text-fill: red;
}
.style3{
    -fx-background-color: green;
     -fx-text-fill: yellow;
}

和控制器:

import javafx.animation.PauseTransition;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.Label;
import javafx.util.Duration;

public class Controller {

    @FXML Label label;
    @FXML Parent root;

    private static final int MIN_VALUE = 1, MAX_VALUE = 3;
    private SimpleIntegerProperty counter = new SimpleIntegerProperty();

    @FXML
    private void initialize() {

         root.getStylesheets().add(getClass().getResource("Root.css").toExternalForm());
        counter = new SimpleIntegerProperty();
        counter.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {
            label.getStyleClass().clear();
            label.getStyleClass().add("style"+counter.get());
        });
        label.textProperty().bind(Bindings.createStringBinding(()->String.valueOf(counter.get()), counter));
        counter.set(1);

        PauseTransition pause = new PauseTransition(Duration.seconds(2));
        pause.setOnFinished(event ->{
            counter.set(counter.get() >= MAX_VALUE ? MIN_VALUE : counter.get()+1);
            pause.play();
        });
        pause.play();
    }
}

选项 3: 使用 PseudoClass 控制样式:
选项 2 的更改:
Root.css:

.root:style1 #label{
    -fx-background-color: red;
    -fx-text-fill: white;
}
.root:style2 #label{
    -fx-background-color: yellow;
    -fx-text-fill: red;
}
.root:style3 #label{
    -fx-background-color: green;
    -fx-text-fill: yellow;
}

和控制器:

import javafx.animation.PauseTransition;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.css.PseudoClass;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.Label;
import javafx.util.Duration;

public class Controller {

    @FXML Label label;
    @FXML Parent root;

    private static final int MAX_VALUE = 3;
    private SimpleIntegerProperty counter = new SimpleIntegerProperty(1);

    @FXML
    private void initialize() {

        root.getStylesheets().add(getClass().getResource("Root.css").toExternalForm());
        counter = new SimpleIntegerProperty();
        counter.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {
            updateStates();
        });

        label.textProperty().bind(Bindings.createStringBinding(()->String.valueOf(counter.get()), counter));
        counter.set(1);

        PauseTransition pause = new PauseTransition(Duration.seconds(2));
        pause.setOnFinished(event ->{
            counter.set(counter.get() >= MAX_VALUE ? 1 : counter.get()+1);
            pause.play();
        });
        pause.play();
    }

    private void updateStates() {
        for( int index = 1; index <= MAX_VALUE; index++){
            PseudoClass pc = PseudoClass.getPseudoClass("style"+String.valueOf(index));
            root.pseudoClassStateChanged(pc, index == counter.get()  ? true : false);
        }
    }
}

【讨论】:

  • hmm ... id 在整个文档中不应该是唯一的吗?
  • 感谢我实施这个的建议,它工作正常。我改变了一点。它更改了类而不是 id,因为 customlabel 可以具有与其他自定义标签相同的文本。
  • 改变样式类或者使用伪类当然更好。选择发布的技术是为了清晰和简单。
  • @kleopatra 你是对的。因此评论“//你可能想在这里实现一些逻辑”。这个简化的演示并没有违反它,但我确实改进了评论措辞。感谢您的评论。
【解决方案2】:

如果你只是想改变Label的背景颜色,根据文本,你也可以像这样创建一个方法,并在需要时为每个Label调用它。

import javafx.scene.control.Label;
import javafx.geometry.Insets;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.paint.Color;    

private void backgroundColorTextDependent(Label label) {
        if (label.getText().equals("1")) {
            label.setBackground(new Background(new BackgroundFill(Color.BLACK, CornerRadii.EMPTY, Insets.EMPTY)));
        } else if (label.getText().equals("2")) {
            label.setBackground(new Background(new BackgroundFill(Color.YELLOW, CornerRadii.EMPTY, Insets.EMPTY)));
        } else if (label.getText().equals("3")) {
            label.setBackground(new Background(new BackgroundFill(Color.GREEN, CornerRadii.EMPTY, Insets.EMPTY)));
        } else {
            label.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-31
    • 2016-01-19
    • 2022-07-13
    • 2022-01-03
    • 1970-01-01
    • 2019-06-15
    • 2013-11-03
    • 2021-01-12
    相关资源
    最近更新 更多