我已经创建了一个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();
}
启动应用程序时,控制台会给我上面描述的异常,但是everthing工作正常。但是,如果应用程序生成异常,则控制台不会显示该异常并且所有内容都已锁定。我做错了什么?
答案 0 :(得分:9)
JavaFX是一个单线程工具包。您永远不应该从后台线程查询或更新UI。因此,您需要使用
将所有调用包装到JFX类中Platform.runLater(new Runnable() {
@Override
public void run() {
// Update/Query the FX classes here
}
});
在您的上下文中,Console.run()
方法中的代码是从JavaFX应用程序线程执行的,因此不应该通过调用controller.appendText()
直接修改UI对象。在您的情况下,所有controller.appendText()
调用都应包含在上面定义的Platform.runLater
结构中。