JavaFX重复子级PieChart [英] JavaFX Duplicate children PieChart

查看:72
本文介绍了JavaFX重复子级PieChart的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个程序,其中饼图中的按钮单击数据会旋转(10时12点的切片会移动到12-2等).下面的代码(kinda)可以工作,它可以旋转,但是会吃到临时切片并创建整个错误段.这是我第一次尝试JavaFX,但我不确定如何管理它.

I'm writing a program in which on button click data in a pie chart rotates (slice on 10-12 o'clock moves to 12-2 etc). Code below (kinda) works, it rotates, but eats the temp slice and creates whole paragraph of errors. It is my first time trying JavaFX and I'm not really sure how to manage that.

    private BorderPane layout;
    private Scene scene;

    ObservableList<PieChart.Data> pieChartData =
            FXCollections.observableArrayList(
                    new PieChart.Data("Post-production age", 424236),
                    new PieChart.Data("Production age", 1030060),
                    new PieChart.Data("Production age2", 1030060),
                    new PieChart.Data("Production age3", 1030060),
                    new PieChart.Data("Pre-production age", 310319));
    PieChart chart = new PieChart(pieChartData);

    @Override public void start(Stage stage) {
        layout = new BorderPane();
        scene = new Scene(layout,720,480);
        stage.setTitle("People");
        stage.setWidth(500);
        stage.setHeight(500);

        Button button = new Button();
        button.setText("rotate");
        layout.setBottom(button);
        layout.setCenter(chart);
        button.setOnAction(e -> {
            rotate();
        });

        chart.setStartAngle(90);
        chart.setTitle("Economical age groups");
        stage.setScene(scene);
        stage.show();
    }
    public  void rotate(){

        ObservableList<PieChart.Data> pieChartDataTemp = pieChartData;
        int sizeOne = pieChartDataTemp.size();
        PieChart.Data tempData = pieChartDataTemp.get(sizeOne-1);
         pieChartDataTemp.add(0,tempData);
         if(pieChartDataTemp.size()>sizeOne) pieChartDataTemp.remove(pieChartDataTemp.size()-1 );

        PieChart chartTemp = new PieChart(pieChartDataTemp);
        layout.setCenter(chartTemp);
        chartTemp.setStartAngle(90);

    }

这是堆栈跟踪:

Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Children: duplicate children added: parent = Chart$1@5cfeee33[styleClass=chart-content]
    at javafx.graphics/javafx.scene.Parent$3.onProposedChange(Parent.java:558)
    at javafx.base/com.sun.javafx.collections.VetoableListDecorator.add(VetoableListDecorator.java:206)
    at javafx.controls/javafx.scene.chart.PieChart.dataItemAdded(PieChart.java:417)
    at javafx.controls/javafx.scene.chart.PieChart.lambda$new$0(PieChart.java:168)
    at javafx.base/com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
    at javafx.base/com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
    at javafx.base/javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
    at javafx.base/javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
    at javafx.base/javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
    at javafx.base/javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
    at javafx.base/javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:155)
    at task.Main.rotate(Main.java:54)
    at task.Main.lambda$start$0(Main.java:39)
(...and so on)

推荐答案

某些背景

JavaFX图表在添加,删除或更新数据时支持动画.但是,启用动画后,节点在动画完成之前,不会从图表中删除用于实际显示数据的信息,这是无法公开观察到的.这意味着您不能像当前所做的那样仅删除PieChart.Data然后立即将其重新添加.当所述Node当前仍是所述Parent的子代时,尝试这样做会导致尝试将Node添加到Parent.如IllegalArgumentException所述,重复的孩子不允许.

Some Background

JavaFX charts support animation when data is added, removed, or updated. However, when animation is enabled, the nodes used to actually display the data aren't removed from the chart until the animation completes—which is not something publicly observable. This means you can't just remove a PieChart.Data and then immediately re-add it, as you're currently doing. Attempting to do that results in trying to add a Node to a Parent when said Node is still currently a child of said Parent. As the IllegalArgumentException you get says, duplicate children are not allowed.

您有此代码(来自#rotate()):

ObservableList<PieChart.Data> pieChartDataTemp = pieChartData;
int sizeOne = pieChartDataTemp.size();
PieChart.Data tempData = pieChartDataTemp.get(sizeOne - 1);
pieChartDataTemp.add(0,tempData);
if (pieChartDataTemp.size() > sizeOne) {
    pieChartDataTemp.remove(pieChartDataTemp.size() - 1);
}

PieChart chartTemp = new PieChart(pieChartDataTemp);
layout.setCenter(chartTemp);
chartTemp.setStartAngle(90);

pieChartDataTemppieChartData都引用相同的ObservableList.因此,当您在0索引处添加tempData时,实际上是将元素添加到当前PieChart中,而该元素仍存在于size() - 1索引中.我试图通过交换addremove调用来解决此问题,但这并不能解决问题,这就是我发现动画妨碍的方式.

Both pieChartDataTemp and pieChartData refer to the same ObservableList. So when you add tempData at the 0 index you're actually adding the element to the current PieChart while it's still present at the size() - 1 index. I tried to fix this by swapping the add and remove calls but that didn't fix the problem—that's how I found out the animations were getting in the way.

您还创建了一个新的PieChart并替换了旧的PieChart.假设我正确理解了您要执行的操作,则没有必要.由于每个PieChart都使用相同的ObservableList.

You also create a new PieChart and replace the old one. This is not necessary, assuming I properly understand what you're trying to do. It may also cause problems since you're using the same ObservableList for each PieChart.

至少有两种解决方案.

一种解决方法是简单地禁用动画:

One fix is to simply disable animations:

yourPieChart.setAnimated(false);

复制PieChart.Data

另一种选择是从旧版本创建一个新的PieChart.Data.这是一个示例:

Copy the PieChart.Data

The other option is to create a new PieChart.Data from the old one. Here's an example:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Button;
import javafx.scene.control.Separator;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {

    private ObservableList<PieChart.Data> createChartData() {
        return FXCollections.observableArrayList(
                new PieChart.Data("Post-production age", 424236),
                new PieChart.Data("Production age", 1030060),
                new PieChart.Data("Production age2", 1030060),
                new PieChart.Data("Production age3", 1030060),
                new PieChart.Data("Pre-production age", 310319)
        );
    }

    @Override
    public void start(Stage primaryStage) {
        PieChart chart = new PieChart(createChartData());
        chart.setStartAngle(90.0);

        Button rotateBtn = new Button("Rotate");
        rotateBtn.setOnAction(event -> {
            event.consume();
            PieChart.Data removed = chart.getData().remove(chart.getData().size() - 1);
            chart.getData().add(0, new PieChart.Data(removed.getName(), removed.getPieValue()));
        });

        VBox root = new VBox(10, rotateBtn, new Separator(), chart);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(20));

        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

}

旋转代码在按钮的onAction处理程序中:

The rotate code is in the onAction handler of the button:

rotateBtn.setOnAction(event -> {
    event.consume();
    PieChart.Data removed = chart.getData().remove(chart.getData().size() - 1);
    chart.getData().add(0, new PieChart.Data(removed.getName(), removed.getPieValue()));
});

请注意,我不会再创建一个PieChart.

Note I don't create another PieChart.

这篇关于JavaFX重复子级PieChart的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆