Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException

Рейтинг: -3Ответов: 1Опубликовано: 10.07.2023

Сделал приложение для анализа места на диске по обучающему видео. Которое позволяет выбрать нужную папку, и посмотреть данные в ней в виде диаграммы. Все хорошо работало, но после добавление кнопки для возращения в предыдущую директорию, стало выводить - Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException. Как исправить данную ошибку?

фрагмент после добавления которого стало выходить исключение:

    BorderPane pane = new BorderPane();
    pane.setTop(button);
    pane.setCenter(pieChart);

class Analyzer:

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;

public class Analyzer {

    private HashMap<String, Long> sizes;

    public Map<String, Long> calculateDirectorySize(Path path) {
        try {
            sizes = new HashMap<>();
            Files.walkFileTree(
                    path,
                    new SimpleFileVisitor<>() {
                        @Override
                        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                            long size = Files.size(file);
                            updateDirSize(file, size);
                            return FileVisitResult.CONTINUE;
                        }

                        @Override
                        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                            return FileVisitResult.SKIP_SUBTREE;
                        }
                    }
            );
            return sizes;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void updateDirSize(Path file, Long size) { 
        String key = file.toString();
        sizes.put(key, size + sizes.getOrDefault(key, 0L));

        Path parent = file.getParent();
        if (parent != null) {
            updateDirSize(parent, size);
        }
    }
}

class Starter:

import DiskAnylizer.ApplicationLogic.Analyzer;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;

import java.io.File;
import java.nio.file.Path;
import java.util.Map;
import java.util.stream.Collectors;

public class Starter extends Application {
    private Stage stage;
    private Map<String, Long> sizes;
    private ObservableList<PieChart.Data> pieChartDate  = FXCollections.observableArrayList();
    private PieChart pieChart;

    public static void main(String[] args) {
        launch(args);
    }
    @Override
    public void start(Stage stage) throws Exception {
        this.stage = stage;
        stage.setTitle("Disk Analyzer");

        Button button = new Button("Choose directory");
        button.setOnAction(event ->  {
            File file = new DirectoryChooser().showDialog(stage);
            String absolutePath = file.getAbsolutePath();
            sizes = new Analyzer().calculateDirectorySize(Path.of(absolutePath));
            buildChart(absolutePath);
        });

        StackPane pane = new StackPane();
        pane.getChildren().add(button);
        stage.setScene(new Scene(pane, 300, 250));
        stage.show();




    }

    private void buildChart(String absolutePath) {
        pieChart = new PieChart(pieChartDate);

        refillChart(absolutePath);

        Button button = new Button(absolutePath);
        button.setOnAction(event -> refillChart(absolutePath));

        BorderPane pane = new BorderPane();
        pane.setTop(button);
        pane.setCenter(pieChart);

        stage.setScene(new Scene(pieChart, 900, 600));
        stage.show();
    }

    private void refillChart(String absolutePath) {
        pieChartDate.clear();
        pieChartDate.addAll(
                sizes.entrySet()
                        .parallelStream()
                        .filter(entry -> {
                            Path parent = Path.of(entry.getKey()).getParent();
                            return parent != null && parent.toString().equals(absolutePath);
                        })
                        .map(entry -> new PieChart.Data(entry.getKey(), entry.getValue()))
                        .collect(Collectors.toList())
        );
        pieChart.getData().forEach(data -> {
            data
                    .getNode()
                    .addEventHandler(
                            MouseEvent.MOUSE_PRESSED,
                            event -> refillChart(data.getName())
                    );
        });
    }
}

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>Desktop-disk-analyzer</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.8</version>
                <configuration>
                    <mainClass>DiskAnylizer.Starter</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>20</version>
        </dependency>
    </dependencies>

</project>

stack trace:

[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------< org.example:Desktop-disk-analyzer >------------------
[INFO] Building Desktop-disk-analyzer 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] >>> javafx-maven-plugin:0.0.8:run (default-cli) > process-classes @ Desktop-disk-analyzer >>>
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ Desktop-disk-analyzer ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ Desktop-disk-analyzer ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] <<< javafx-maven-plugin:0.0.8:run (default-cli) < process-classes @ Desktop-disk-analyzer <<<
[INFO] 
[INFO] 
[INFO] --- javafx-maven-plugin:0.0.8:run (default-cli) @ Desktop-disk-analyzer ---
Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: PieChart@5dda5c5e[styleClass=chart]is already inside a scene-graph and cannot be set as root
    at javafx.graphics@20/javafx.scene.Scene$8.invalidated(Scene.java:1224)
    at javafx.base@20/javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
    at javafx.base@20/javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:147)
    at javafx.graphics@20/javafx.scene.Scene.setRoot(Scene.java:1196)
    at javafx.graphics@20/javafx.scene.Scene.<init>(Scene.java:360)
    at javafx.graphics@20/javafx.scene.Scene.<init>(Scene.java:240)
    at DiskAnylizer.Starter.buildChart(Starter.java:66)
    at DiskAnylizer.Starter.lambda$start$0(Starter.java:41)
    at javafx.base@20/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at javafx.base@20/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:232)
    at javafx.base@20/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:189)
    at javafx.base@20/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base@20/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base@20/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base@20/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base@20/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base@20/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base@20/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base@20/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base@20/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.base@20/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics@20/javafx.scene.Node.fireEvent(Node.java:8944)
    at javafx.controls@20/javafx.scene.control.Button.fire(Button.java:203)
    at javafx.controls@20/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:207)
    at javafx.controls@20/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
    at javafx.base@20/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:247)
    at javafx.base@20/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at javafx.base@20/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:232)
    at javafx.base@20/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:189)
    at javafx.base@20/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base@20/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base@20/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base@20/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base@20/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base@20/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base@20/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base@20/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base@20/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.base@20/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics@20/javafx.scene.Scene$MouseHandler.process(Scene.java:3980)
    at javafx.graphics@20/javafx.scene.Scene.processMouseEvent(Scene.java:1890)
    at javafx.graphics@20/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2704)
    at javafx.graphics@20/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:411)
    at javafx.graphics@20/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:301)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at javafx.graphics@20/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:450)
    at javafx.graphics@20/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424)
    at javafx.graphics@20/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:449)
    at javafx.graphics@20/com.sun.glass.ui.View.handleMouseEvent(View.java:551)
    at javafx.graphics@20/com.sun.glass.ui.View.notifyMouse(View.java:937)
    at javafx.graphics@20/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics@20/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:185)
    at java.base/java.lang.Thread.run(Thread.java:833)

Ответы

▲ 0Принят

в class.Starter вместо pieChart в аргументы setScene нужно передать объявленный BorderPane pane.

было:

stage.setScene(new Scene(pieChart, 900, 600));

стало:

stage.setScene(new Scene(pane, 900, 600));