JavaFX Duplicate детей PieChart - PullRequest
4 голосов
/ 24 июня 2019

Я пишу программу, в которой по нажатию кнопки данные на круговой диаграмме вращаются (срез на 10-12 часов перемещается в 12-2 и т. Д.). Код ниже (вроде) работает, он вращается, но ест временный фрагмент и создает целый абзац ошибок. Я впервые пробую 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 Ответ

4 голосов
/ 25 июня 2019

Некоторые фоновые изображения

Диаграммы JavaFX поддерживают анимацию при добавлении, удалении или обновлении данных.Однако, когда анимация включена, узлы , используемые для фактического отображения данных , не удаляются с диаграммы до тех пор, пока анимация не завершится, что не является чем-то общедоступным.Это означает, что вы не можете просто удалить PieChart.Data, а затем немедленно добавить его, как вы это делаете в настоящее время.Попытка сделать это приводит к попытке добавить Node к Parent, когда указанный Node все еще является потомком указанного Parent.Как говорится в IllegalArgumentException, дубликаты детей запрещены .


Проблемы в вашем коде

У вас есть этот код (из #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);

И pieChartDataTemp, и pieChartData относятся к одному и тому же ObservableList.Поэтому, когда вы добавляете tempData в индекс 0, вы фактически добавляете элемент к текущему PieChart, пока он все еще присутствует в индексе size() - 1.Я попытался исправить это, поменяв местами вызовы add и remove, но это не решило проблему - вот как я обнаружил, что анимация мешает.

Вы также создаете новый PieChart и замените старую.Это не обязательно, если я правильно понимаю, что вы пытаетесь сделать.Это также может вызвать проблемы, поскольку вы используете один и тот же ObservableList для каждого PieChart.


Решения

Существует как минимум два решения.

Отключить анимацию

Одно из исправлений - просто отключить анимацию :

yourPieChart.setAnimated(false);

Скопировать 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...