JavaFX PieChart 图例颜色变化

JavaFX PieChart Legend Color change

我需要更改 PieChart Legend 中圆圈的颜色。我不知道如何访问 PieChart 的 属性。例如,我可以更改标签 Legend 中文本的颜色,我认为这接近于解决方案。

它显示了我要更改的内容:

@FXML
public PieChart chart;
public ObservableList<PieChart.Data> pieChartData = FXCollections.observableArrayList();

public void chartLoad() { 

    pieChartData.clear();
    List<String> colorList = new ArrayList<>();
    for(int i = 0; i < categoryList.getSize(); i++) {
        if(categoryList.getByIndex(i).getValue() > 0) {
            PieChart.Data data = new PieChart.Data(categoryList.getByIndex(i).getName(), 
                categoryList.getByIndex(i).getValue());
            pieChartData.add(data);
            data.getNode().setStyle("-fx-pie-color: " + 
                categoryList.getByIndex(i).getColor().getName());
            colorList.add(categoryList.getByIndex(i).getColor().getName());
        }
    }

    Set<Node> items = chart.lookupAll("Label.chart-legend-item");
    int i = 0;
    for(Node item : items) {
        Label label = (Label) item;
        label.setText("sampleText");
        label.setStyle("-fx-text-fill: " + colorList.get(i)); 
        System.out.println(label.getChildrenUnmodifiable().toString());
        i++;
    }
    chart.setData(pieChartData);
}

感谢您以后的评论和回答。

动态地为图表分配颜色有点麻烦。如果你有一组固定的颜色,没有从数据到颜色的预定义映射,你可以只使用外部样式 sheet,但做任何其他事情都需要(据我所知)一点技巧.

默认 modena.css 样式 sheet 定义八种常量颜色,CHART_COLOR_1CHART_COLOR_8。饼图中的节点,包括 "pie slices" 和图例中的颜色样本,被分配了一个样式 class 从八个 classes default-color0default-color7.默认情况下,这些样式 class 中的每一个都将 -fx-pie-color 设置为常量之一。不幸的是,如果饼图中的数据发生变化,这些从 default-colorxCHART_COLOR_y 的映射会以未记录的方式发生变化。

因此,我能找到的最适合您的情况的方法是:

  • 将新数据添加到图表
  • 添加所有数据后,为每个数据查找添加到数据节点
  • 的样式class
  • 查找图表中具有该样式的所有节点class(这也会给出图例样本)
  • 将这些节点的 -fx-pie-color 更新为所需的颜色

这里的最后一个陷阱是您需要确保图例已添加到图表中,并且 CSS 已应用于图表,以便查找有效。

public void chartLoad() { 

    pieChartData.clear();
    List<String> colors = new ArrayList<>();
    for(int i = 0; i < categoryList.getSize(); i++) {
        if(categoryList.getByIndex(i).getValue() > 0) {
            PieChart.Data data = new PieChart.Data(categoryList.getByIndex(i).getName(), 
                categoryList.getByIndex(i).getValue());
            pieChartData.add(data);
            colors.add(categoryList.getByIndex(i).getColor().getName());
        }
    }

    chart.setData(pieChartData);
    chart.requestLayout();
    chart.applyCSS();

    for (int i = 0 ; i < pieChartData.size() ; i++) {
        PieChart.Data d = pieChartData.get(i);
        String colorClass = "" ;
        for (String cls : d.getNode().getStyleClass()) {
            if (cls.startsWith("default-color")) {
                colorClass = cls ;
                break ;
            }
        }
        for (Node n : chart.lookupAll("."+colorClass)) {
            n.setStyle("-fx-pie-color: "+colors.get(i));
        }
    }

}

这是此方法的快速、完整的演示:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class PieChartTest extends Application {

    private final Random rng = new Random();

    @Override
    public void start(Stage primaryStage) throws Exception {
        PieChart chart = new PieChart();
        Button button = new Button("Generate Data");
        button.setOnAction(e -> updateChart(chart));
        BorderPane root = new BorderPane(chart);
        HBox controls = new HBox(button);
        controls.setAlignment(Pos.CENTER);
        controls.setPadding(new Insets(5));
        root.setTop(controls);

        Scene scene = new Scene(root, 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void updateChart(PieChart chart) {
        chart.getData().clear();
        int numValues = 4 + rng.nextInt(10);

        List<String> colors = new ArrayList<>();
        List<PieChart.Data> data = new ArrayList<>();



        for (int i = 0 ; i < numValues ; i++) {
            colors.add(getRandomColor());
            PieChart.Data d = new PieChart.Data("Item "+i, rng.nextDouble() * 100);
            data.add( d );
            chart.getData().add(d) ;
        }

        chart.requestLayout();
        chart.applyCss();

        for (int i = 0 ; i < data.size() ; i++) {
            String colorClass = "" ;
            for (String cls : data.get(i).getNode().getStyleClass()) {
                if (cls.startsWith("default-color")) {
                    colorClass = cls ;
                    break ;
                }
            }
            for (Node n : chart.lookupAll("."+colorClass)) {
                n.setStyle("-fx-pie-color: "+colors.get(i));
            }
        }
    }

    private String getRandomColor() {
        Color color = Color.hsb(rng.nextDouble() * 360, 1, 1);
        int r = (int) (255 * color.getRed()) ;
        int g = (int) (255 * color.getGreen());
        int b = (int) (255 * color.getBlue()) ;

        return String.format("#%02x%02x%02x", r, g, b) ;
    }


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

这确实有点hack,所以显然欢迎更好的解决方案。