如何通过属性改变组件的样式?
How to change the style of components by their attributes?
我想在 javafx 中显示不同的标签,并且我想根据它们的文本设置样式。我添加了一个 css 文件并设置了标签的 class。然后我检查了fxml,发现文本保存在文本属性中。
我查看了正常的 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 中完成这项工作?
If I would change the text it would also automatically change the
style
选项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="""" />
</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;
}
测试class:
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();
}
}
方案二:通过改变样式来控制样式-class
使用与选项 1 相同的测试 class。
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="" "" />
</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);
}
}
}
如果你只是想改变 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)));
}
我想在 javafx 中显示不同的标签,并且我想根据它们的文本设置样式。我添加了一个 css 文件并设置了标签的 class。然后我检查了fxml,发现文本保存在文本属性中。
我查看了正常的 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 中完成这项工作?
If I would change the text it would also automatically change the style
选项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="""" />
</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;
}
测试class:
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();
}
}
方案二:通过改变样式来控制样式-class
使用与选项 1 相同的测试 class。
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="" "" />
</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);
}
}
}
如果你只是想改变 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)));
}