JavaFX复制子PieChart

时间:2019-06-24 20:28:57

标签: java javafx

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

    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)

1 个答案:

答案 0 :(得分:4)

某些背景

添加,删除或更新数据时,JavaFX图表支持动画。但是,启用动画后,nodes used to actually display the data不会从图表中删除,直到动画完成为止-这是无法公开观察到的。这意味着您不能像当前所做的那样仅删除PieChart.Data然后立即重新添加。如果说的Node当前仍是所说的Parent的孩子,尝试这样做会导致将Node添加到Parent中。如您所言IllegalArgumentExceptionduplicate 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。因此,当您在tempData索引处添加0时,实际上是将元素添加到当前PieChart,而该元素仍在size() - 1索引中。我尝试通过交换addremove调用来解决此问题,但这并不能解决问题,这就是我发现动画妨碍了解决方法。

您还将创建一个新的PieChart并替换旧的ObservableList。假设我正确理解了您要执行的操作,则没有必要。由于每个PieChart使用相同的yourPieChart.setAnimated(false); ,因此也会引起问题。


解决方案

至少有两种解决方案。

禁用动画

一种解决方法是简单地disable animations

PieChart.Data

复制PieChart.Data

另一种选择是从旧版本创建新的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

旋转代码在按钮的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

请注意,我不会再创建一个 <div v-for="parent_index in 7" :key="parent_index" class="flex justify-center"> <div class="square"> <div class="square-content" style="vertical-align:middle;">User {{ parent_index }}</div> </div> <div v-for="index in 14" :key="index" class="square bg-success" @click="changeDayState(dayCode,$event)"> </div> </div>