2013-08-22 28 views
1

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

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的作品。但是,如果应用程序生成异常,则控制台不会显示它,并且所有内容都已锁定。我做错了什么?

回答

9

JavaFX是一个单线程工具包。您不应该从后台线程查询或更新UI。因此,你需要用

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

在您的上下文来包装所有的JFX类的调用,在Console.run()方法的代码被执行过JavaFX应用程序线程,因此它不应该通过调用controller.appendText()直接修改UI对象。在你的情况下,所有的controller.appendText()调用都应该包含在上面定义的Platform.runLater结构中。

+0

对不起,但我不明白如何在我的上下文中使用此代码。 – Eugene

+1

@Eugene我编辑了答案,解释如何在你的上下文中使用'Platform.runLater'。 – jewelsea

+0

@jewelsea非常感谢 – Eugene