1

我制作了一个 Java/JavaFX 控制台,现在我遇到了一个例外:Console reports an Internal error.The error is: java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-5. 控制台代码:

package core.console;
import javafx.concurrent.Service;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;

import java.io.*;
import java.util.ResourceBundle;

public class Console implements Runnable{
    private Console(ResourceBundle resourceBundle) throws IOException {
        FXMLLoader loader = new FXMLLoader(this.getClass().getResource("Console.fxml"), resourceBundle);
        Parent root = (Parent) loader.load();
        controller = loader.getController();
        Scene scene = new Scene(root);
        stage = new Stage();
        stage.setScene(scene);
        textArea = controller.getTextArea();
        show();

        PipedOutputStream pout=new PipedOutputStream(this.pin);
        System.setOut(new PrintStream(pout,true));

        PipedOutputStream pout2=new PipedOutputStream(this.pin2);
        System.setErr(new PrintStream(pout2,true));

        System.setIn(new PipedInputStream(this.pout3));

        reader = new Thread(this);
        reader.setDaemon(true);
        reader.start();

        reader2 = new Thread(this);
        reader2.setDaemon(true);
        reader2.start();
    }   

    public static Console getInstance(ResourceBundle resourceBundle) {
        if (console == null) {
            try {
                console = new Console(resourceBundle);
            } catch (IOException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
        return console;
    }

    public void show() {
        stage.show();
    }

    @Override
    public synchronized void run()
    {
        try
        {
            while (Thread.currentThread()==reader)
            {
                try {
                    this.wait(100);
                } catch(InterruptedException ie) {}
                if (pin.available()!= 0)
                {
                    String input=this.readLine(pin);
                    controller.appendText(input);
                }
                if (quit) return;
            }

            while (Thread.currentThread()==reader2)
            {
                try {
                    this.wait(100);
                } catch(InterruptedException ie) {}
                if (pin2.available()!= 0)
                {
                    String input = this.readLine(pin2);
                    controller.appendText(input);
                }
                if (quit) return;
            }
        } catch (Exception e)
        {
            controller.appendText("\nConsole reports an Internal error.");
            controller.appendText("The error is: "+e);
        }

    }

    private synchronized String readLine(PipedInputStream in) throws IOException
    {
        String input="";
        do
        {
            int available=in.available();
            if (available==0) break;
            byte b[]=new byte[available];
            in.read(b);
            input=input+new String(b,0,b.length);
        }while( !input.endsWith("\n") &&  !input.endsWith("\r\n") && !quit);
        return input;
    }   

    private static Console console = null;
    private ConsoleController controller;
    private Stage stage;
    private TextArea textArea;
    private Thread reader;
    private Thread reader2;

    private final PipedInputStream pin=new PipedInputStream();
    private final PipedInputStream pin2=new PipedInputStream();
    private final PipedOutputStream pout3=new PipedOutputStream();


}

启动应用程序时,控制台给了我上述异常,但一切正常。但是如果应用程序产生了异常,控制台不会显示它并且一切都被锁定了。我做错了什么?

4

1 回答 1

9

JavaFX 是一个单线程工具包。您永远不应该从后台线程查询或更新 UI。因此,您需要将所有对 JFX 类的调用包装为

Platform.runLater(new Runnable() {
   @Override
   public void run() {
      // Update/Query the FX classes here
   }
});

在您的上下文中,Console.run()方法中的代码是在 JavaFX 应用程序线程之外执行的,因此不应通过调用controller.appendText(). 在您的情况下,所有controller.appendText()调用都应包含在Platform.runLater上面定义的构造中。

于 2013-08-22T18:10:53.000 回答