JavaFX线性渐变的重复行为

3

Javafx的线性渐变重复似乎是反射颜色而不是重复。

我编写了一个简单的应用程序,展示了在自定义节点(StackPane)上使用线性渐变和重复创建条纹图案时看到的情况。在我的应用程序中,它们被添加为覆盖物到XYChart上,并且它们的高度是可变的。使用矩形并不起作用,这就是为什么我使用Stackpane并在其上设置样式而不是通过编程方式创建LinearGradient的原因。 颜色列表是动态的,并在应用程序中大小不同。 问题是linear-gradient如何翻转列表并在每次重复时反映颜色,而不只是重复。

此链接描述了类似的问题,但是仅添加无限制的停止看起来像是对我的问题的一种混乱的解决方案,最好只添加一次颜色并重复。

线性渐变在Javafx中的CSS中的重复

java.util.List;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            BorderPane root = new BorderPane();
            List<Color> colors = Arrays.asList( Color.RED,Color.BLUE,Color.YELLOW,Color.GREEN);

            StackPane stackPane = new StackPane();

            stackPane.setStyle(getLinearGradientStyle(colors));
            root.setCenter(stackPane);
            Scene scene = new Scene(root, 400, 400);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getLinearGradientStyle(List<Color> colors) {
        StringBuilder stringBuilder = new StringBuilder("-fx-background-color: linear-gradient(from 0px 0px to 10px 10px, repeat,");
        for (int i = 0; i < colors.size(); i++) {
            stringBuilder.append("rgb(")
                    .append((int) (colors.get(i).getRed() * 255)).append(",")
                    .append((int) (colors.get(i).getGreen() * 255)).append(",")
                    .append((int) (colors.get(i).getBlue() * 255))
                    .append(")")
                    .append(" ").append(getPercentage(i+1, colors.size()+1) );
            if (i < colors.size() - 1) {
                stringBuilder.append(",");
            }
        }
        stringBuilder.append(");");
        System.out.println("Main.getLinearGradientStyle():"+stringBuilder);
        return stringBuilder.toString();
    }

    private String getPercentage(float i, int size) {
        return  (((1.0f / size) * 100 )*i)+ "%";
    }


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

}

这是一个使用repeating-linear-gradient的CSS3示例: https://tympanus.net/codrops/css_reference/repeating-linear-gradient/ 在页面向下滚动,您会看到以下文本:将创建一个条纹背景,其中每个线性渐变都是三条纹理渐变,无限重复(这是示例)。
我的示例使用了对角线图案,这正是我所需要的,但上面的示例展示了我想在普通 CSS 中看到的具有不反射的连续色彩。谢谢任何帮助。

该bug将在JavaFX 13中得到修复。 - Slaw
1个回答

5
这似乎是一个bug。如果你运行下面的示例(将CSS移到一个文件中):

Main.java

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Region;
import javafx.stage.Stage;


public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        Region region = new Region();
        region.backgroundProperty().addListener((obs, ov, nv) ->
                System.out.println(nv.getFills().get(0).getFill()));

        Scene scene = new Scene(region, 500, 300);
        scene.getStylesheets().add("Main.css");

        primaryStage.setScene(scene);
        primaryStage.show();
    }

}

Main.css

.root {
    -fx-background-color: linear-gradient(from 0px 0px to 10px 10px, repeat, red 20%, blue 40%, yellow 60%, green 80%);
}

您将看到以下内容打印出来:
linear-gradient(from 0.0px 0.0px to 10.0px 10.0px, reflect, 0xff0000ff 0.0%, 0xff0000ff 20.0%, 0x0000ffff 40.0%, 0xffff00ff 60.0%, 0x008000ff 80.0%, 0x008000ff 100.0%)

从CSS中可以看出,尽管使用了 "repeat",但创建的 LinearGradient 仍然使用了 "reflect"。

关于这个 bug,你可能无法自己解决,但如果你不介意在代码(或者很可能是FXML)中设置背景,那么以下代码应该能够满足你的需求:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.stage.Stage;


public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        LinearGradient gradient = new LinearGradient(0, 0, 10, 10, false, CycleMethod.REPEAT,
                new Stop(0.2, Color.RED),
                new Stop(0.4, Color.BLUE),
                new Stop(0.6, Color.YELLOW),
                new Stop(0.8, Color.GREEN)
        );

        Region region = new Region();
        region.setBackground(new Background(new BackgroundFill(gradient, null, null)));

        Scene scene = new Scene(region, 500, 300);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

}

你可以将LinearGradient的创建移入一个方法中,该方法接受任意数量的Color,就像你目前正在做的一样。
如果你感兴趣,我认为bug位于javafx.css.CssParser的第1872行附近(在JavaFX 12中)。
CycleMethod cycleMethod = CycleMethod.NO_CYCLE;
if ("reflect".equalsIgnoreCase(arg.token.getText())) {
    cycleMethod = CycleMethod.REFLECT;
    prev = arg;
    arg = arg.nextArg;
} else if ("repeat".equalsIgnoreCase(arg.token.getText())) {
    cycleMethod = CycleMethod.REFLECT;
    prev = arg;
    arg = arg.nextArg;
}

正如您所看到的,在文本等于"repeat"时,它错误地将CycleMethod设置为REFLECT

已经提交了一个缺陷报告:JDK-8222222 (GitHub #437)。修复版本:openjfx13


嘿,太好了,感谢指出那个错误。我已经实现了你的建议版本,它运行得非常好 :) 非常感谢你。 - rickybobby
似乎自Java 8以来就存在这个错误。然而,最好将其提交,以便得到确认和修复。 - José Pereda
@JoséPereda 如我在答案末尾提到的,我已经提交了一个错误报告——只是还没有得到反馈。虽然我已经将其提交给JBS,但我是否也应该在GitHub上提出这个问题? - Slaw
理想情况下,一旦您获得了JBS问题的批准,请在GitHub上提交错误报告,并附上该问题的ID。如果由于某种原因您没有收到反馈,请继续将其提交到GitHub并提及它。 - José Pereda
@JoséPereda完成。在答案末尾添加了链接。 - Slaw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接