2013-07-31 48 views
3

有必要制作一个自定义控制台。我有以下代码:如何制作自定义的Java/JavaFX控制台?

public class Console extends OutputStream{ 

private Console(ResourceBundle resourceBundle) throws IOException { 
    FXMLLoader loader = new FXMLLoader(this.getClass().getResource("Console.fxml"), resourceBundle); 
    controller = loader.getController(); 
    Scene scene = new Scene((Parent) loader.load()); 
    stage = new Stage(); 
    stage.setScene(scene); 
    show(); 
} 

@Override 
public void write(int b) throws IOException { 
    controller.append(b); 
} 

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(); 
} 

private static Console console = null; 
private ConsoleController controller; 
private Stage stage; 
} 

控制器文件:

public class ConsoleController implements Initializable { 

@Override 
public void initialize(URL url, ResourceBundle resourceBundle) { 
} 

@FXML 
public void append(int i) { 
    textArea.appendText(String.valueOf((char) i)); 
} 

@FXML 
private TextArea textArea; 
} 

而所有这些都是从被称为 '开始()':

@Override 
public void start(Stage primaryStage) throws IOException { 
    ... 
    System.setErr(new PrintStream(Console.getInstance(rb))); 
} 

在异常没有被印在Console.fxmltextArea,但引发以下异常:

异常在线程“的JavaFX应用程序线程” 例外:显示java.lang.NullPointerException在线程“的JavaFX应用程序线程”

什么我做错了从UncaughtExceptionHandler的抛出?

------ 编辑 --------

理解,它是需要使用多个线程后,我有以下代码:

public class Console{ 
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); 
    show(); 

    if (errorOutputThread != null) { 
     errorOutputThread.interrupt(); 
     try { 
      errorOutputThread.join(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 
     } 
     errorOutputThread = null; 
    } 

    if (outOutputThread != null) { 
     outOutputThread.interrupt(); 
     try { 
      outOutputThread.join(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 
     } 
     outOutputThread = null; 
    } 

    System.err.flush(); 
    System.out.flush(); 

    outPipedInputStream = new PipedInputStream(); 
    outPipedOutputStream = new PipedOutputStream(outPipedInputStream); 
    System.setOut(new PrintStream(outPipedOutputStream)); 

    errorPipedInputStream = new PipedInputStream(); 
    errorPipedOutputStream = new PipedOutputStream(errorPipedInputStream); 
    System.setErr(new PrintStream(errorPipedOutputStream)); 

    outOutputThread = new Thread(new ConsoleStream(outPipedInputStream, "OUT")); 
    outOutputThread.setDaemon(true); 
    outOutputThread.start(); 

    errorOutputThread = new Thread(new ConsoleStream(errorPipedInputStream, "ERROR")); 
    errorOutputThread.setDaemon(true); 
    errorOutputThread.start(); 

    controller.appendText("Start Console"); 

} 

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(); 
} 

private class ConsoleStream implements Runnable { 
    private ConsoleStream(InputStream in, String type) { 
     inputStream = in; 
     this.type = type; 
    } 

    public void run() { 
     try { 
      InputStreamReader is = new InputStreamReader(inputStream); 
      BufferedReader br = new BufferedReader(is); 
      String read = null; 
      read = br.readLine(); 
      while(read != null) { 
       controller.appendText(read + "\n"); 
       read = br.readLine(); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 
     } 
     controller.appendText("Thread" + type + "started"); 

    } 

    private final InputStream inputStream; 
    private String type; 
} 

private static Console console = null; 
private ConsoleController controller; 
private Stage stage; 
private PrintStream printStream; 
private PipedOutputStream customPipedOutputStream; 
private PipedOutputStream errorPipedOutputStream; 
private PipedOutputStream outPipedOutputStream; 
private PipedInputStream customPipedInputStream; 
private PipedInputStream errorPipedInputStream; 
private PipedInputStream outPipedInputStream; 
private Thread customOutputThread; 
private Thread outOutputThread; 
private Thread errorOutputThread; 
} 

但结果只是:“启动控制台”,没有结果controller.appendText("Thread" + type + "started");,所以看起来这个线程没有启动。但为什么?

+0

东西是空(我不知道是什么)。 [Java 8](http://jdk8.java.net/download.html)允许你[为JavaFX应用程序线程设置未捕获的异常处理程序](https://javafx-jira.kenai.com/browse/RT -15332)。也许如果你在Java 8中测试你的应用程序并设置了一个未捕获的异常处理程序,你将能够获得更多的信息(如堆栈跟踪),这可能会帮助你调试你的问题。 – jewelsea

+0

您可能也对[系统错误和系统输出控制台记录器](https://github.com/jewelsea/conception/blob/master/src/org/jewelsea/conception/LogArea.java)感兴趣,我为JavaFX迷你IDE项目。这可能不是处理这种问题的最有效的方式,但它对我有效。 – jewelsea

+0

@jewelsea:我使用了你的记录器代码,并且明白我需要单独的控制台线程。现在我有另一个问题 - 这些线程不想开始。 – Eugene

回答

2

我认为你必须加载窗体,然后才能拿到控制器实例

FXMLLoader loader = new FXMLLoader(this.getClass().getResource("Console.fxml"),resourceBundle); 
Parent p = (Parent) loader.load() 
controller = loader.getController(); 
Scene scene = new Scene(p);