Search code examples
javaswingjavafxlegendpie-chart

How to restrict legend size and making it scrollable with piechart? and javafx layouts


I integrated javafx piechart on my swing panel its working fine, but my data list is too big to fit in the legend and the legend is expanding which causes the piechart getting smaller. Id like to make it scrollable but couldnt find any solution. Im new to javafx.

Also what layout would you suggest for piechart panel and scene to fit in the jpanel? As you see my piechart panel doesnt fill the scene. I dont want my chart to shrink.

public PieChartPanel() {
    this.setLayout(new BorderLayout());
    add(new JScrollPane(getJfxPanel()), BorderLayout.CENTER);
}

public JFXPanel getJfxPanel() {
    if (jfxPanel == null) {
        jfxPanel = new JFXPanel();
        jfxPanel.setScene(getScene());
    }
    return jfxPanel;
}

public Scene getScene() {
    if (scene == null) {
        Group root = new Group();
        scene = new Scene(root, Color.ALICEBLUE);

        javafx.scene.control.ScrollPane scroll = new ScrollPane();
        scroll.setFitToHeight(true);
        scroll.setFitToWidth(true);
        scroll.setContent(getPieChart());

        root.getChildren().addAll(scroll);

    }
    return scene;
}

private PieChart getPieChart() {
    if (pieChart == null) {
        ObservableList<PieChart.Data> pieChartData = FXCollections.observableArrayList();
        pieChart = new PieChart(pieChartData);
        pieChart.setTitle("Toplam Talep (Ünite) Grafiği");
        pieChart.setLabelLineLength(20);
        pieChart.setLegendSide(Side.RIGHT);
        pieChart.setClockwise(true);
    }
    return pieChart;
}

one column legend

one column legend

2 column legend causes chart to shrink

2 column legend causes chart to shrink


Solution

  • If you extend PieChart you can access the Legend directly as it is protected, see : Chart

    By doing that you can do something along these lines:

    public class CustomPieChart extends PieChart {
        public CustomPieChart(ObservableList<PieChart.Data> data){
            super(data);
            setLabelLineLength(20);
            createScrollableLegend();
            setLegendSide(Side.RIGHT);
            setClockwise(true);
        }
    
        private void createScrollableLegend(){
            Legend legend = (Legend) getLegend();
            if(legend != null){
                legend.setPrefWidth(100);
                ScrollPane scrollPane = new ScrollPane(legend);
                scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
                scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
                scrollPane.maxHeightProperty().bind(heightProperty());
                setLegend(scrollPane);
            }
        }
    }
    

    Note: If you go for this approach, I recommend updating this: legend.setPrefWidth(100); to be more specific to your LegendItem's. As this won't be the best solution for large display names


    By substituting the above into your code and adding a few test items to cause the need for the scroll bars, I got the following:

    enter image description here


    Layout wise I don't think you need the Group and scroll panes you're currently using. If you update your getScene() method to the below you should see a small improvement:

    public Scene getScene() {
        VBox root = new VBox();
        Scene scene = new Scene(root, Color.ALICEBLUE);
        root.getChildren().addAll(getPieChart());
        return scene;
    }
    

    For further improvements hopefully the following posts can help: