10

Answer : JavaFX append text to TextArea throws Exception

I have a thread that calculates the size of a directory.

I use walkFileTree for this.

To get some info, I append the actuall file to a textarea.

But when I have a lot of files (ex. > 300) I got

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

Here is the code:

private void startScheduledExecutorService() {

        Thread dt = new Thread(new Runnable() {
            public void run() {
                try {
                    taStatus.appendText("Dateien werden ermittelt\n");
                    Files.walkFileTree(quellOrdner.toPath(), new SimpleFileVisitor<Path>() {
                        @Override
                        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                            size += attrs.size();
                            files++;
                            taStatus.appendText(file.toString() + "\n");
                            return FileVisitResult.CONTINUE;
                        }

                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }, "dt");
        dt.setDaemon(true);
        dt.start();
    }

When I create an ArrayList and add each file to it and append this ArrayList (each entry in a row) to the TextArea, it is working.

It looks like a problem with the thread speed ?

The full Exception

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at com.sun.javafx.text.PrismTextLayout.addTextRun(PrismTextLayout.java:755)
    at com.sun.javafx.text.GlyphLayout.addTextRun(GlyphLayout.java:121)
    at com.sun.javafx.text.GlyphLayout.breakRuns(GlyphLayout.java:191)
    at com.sun.javafx.text.PrismTextLayout.buildRuns(PrismTextLayout.java:770)
    at com.sun.javafx.text.PrismTextLayout.layout(PrismTextLayout.java:1021)
    at com.sun.javafx.text.PrismTextLayout.ensureLayout(PrismTextLayout.java:223)
    at com.sun.javafx.text.PrismTextLayout.getBounds(PrismTextLayout.java:246)
    at javafx.scene.text.Text.getLogicalBounds(Text.java:358)
    at javafx.scene.text.Text.impl_computeGeomBounds(Text.java:1168)
    at javafx.scene.Node.updateGeomBounds(Node.java:3556)
    at javafx.scene.Node.getGeomBounds(Node.java:3509)
    at javafx.scene.Node.getLocalBounds(Node.java:3457)
    at javafx.scene.Node.updateTxBounds(Node.java:3620)
    at javafx.scene.Node.getTransformedBounds(Node.java:3403)
    at javafx.scene.Node.updateBounds(Node.java:538)
    at javafx.scene.Parent.updateBounds(Parent.java:1706)
    at javafx.scene.Parent.updateBounds(Parent.java:1706)
    at javafx.scene.Parent.updateBounds(Parent.java:1706)
    at javafx.scene.Parent.updateBounds(Parent.java:1706)
    at javafx.scene.Parent.updateBounds(Parent.java:1706)
    at javafx.scene.Parent.updateBounds(Parent.java:1706)
    at javafx.scene.Parent.updateBounds(Parent.java:1706)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2404)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:314)
    at com.sun.javafx.tk.Toolkit$$Lambda$178/156290868.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:313)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:340)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:525)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:505)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$400(QuantumToolkit.java:334)
    at com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda$47/104706045.run(Unknown Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at com.sun.glass.ui.gtk.GtkApplication.lambda$null$48(GtkApplication.java:139)
    at com.sun.glass.ui.gtk.GtkApplication$$Lambda$43/1086508417.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)
Community
  • 1
  • 1
Garog
  • 315
  • 1
  • 5
  • 15
  • You get that exception from which line? – user253751 Jun 16 '15 at 09:51
  • nowhere in my code, i added the full Exception – Garog Jun 16 '15 at 09:57
  • @user3710098 If taStatus is some ui element, you can try to add `Platform.runLater(() -> taStatus.appendText());` – varren Jun 16 '15 at 10:51
  • taStatus is a JavaFX TextArea. i will try it with your suggestion – Garog Jun 16 '15 at 11:15
  • that helped to get rid of the error, but freezes my application. but then i don't need a extra thread for that result. so it is really a problem with updating the ui elements, then i will try to code a workaround (just update every 10 elements or something) – Garog Jun 16 '15 at 11:26
  • 5
    as a strict rule, ui elements must be accessed on the fxApplication thread. Your snippet violates that rule - the actual behaviour is undetermined, nasty errors are certain :-) To pass results from a background thread (like your collecting the files, fi.) into the fx thread, have a look at the fx concurrency package – kleopatra Jun 22 '15 at 09:54
  • exactly what i needed ! thx – Garog Jun 23 '15 at 14:29

1 Answers1

17

Ran into same error and as kleopatra's comment stated, FX textarea must be accessed on FX thread.

For simple cases, use Platform.runLater with Java 8 Lambda:

javafx.application.Platform.runLater( () -> taStatus.appendText(file.toString() + "\n") );

If you have many log messages, instead of flooding the FX thread it would be better to buffer them and update TextArea less frequently. Here is an example: https://stackoverflow.com/a/31414801/3710098

Community
  • 1
  • 1
Sheepy
  • 17,324
  • 4
  • 45
  • 69
  • 1
    that works if you don't add a lot, take a look here, it explains why runLater is not the best choice http://stackoverflow.com/a/31414801/3710098 – Garog Jul 16 '15 at 11:19
  • @Garog You did your research well :) I also cache my messages but I prefer a simple answer. That is a good one; I have linked to it. – Sheepy Jul 17 '15 at 05:32