2015-11-03 333 views
0

EDIT 4

我创建了一个简单的例子,应该给你发生的事情,现在的想法产生。JavaFX的:控制台输出重定向到文本区是在SceneBuilder

现在发生的事情是,只要我点击按钮向TextArea打印“HELLO WORLD”,程序就会挂起并使用100%的CPU。 Eclipse控制台面板中也没有输出。

Main.java

public class Main extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     try { 
      Parent root = FXMLLoader.load(getClass().getResource("/application/test.fxml")); 
      Scene scene = new Scene(root); 
      primaryStage.setScene(scene); 
      primaryStage.show(); 


     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

MainController.java

public class MainController { 

    @FXML 
    private TextArea console; 
    private PrintStream ps = new PrintStream(new Console(console)); 

    public void button(ActionEvent event) { 
     System.setOut(ps); 
     System.setErr(ps); 
     System.out.println("Hello World"); 
    } 

    public class Console extends OutputStream { 
     private TextArea console; 

     public Console(TextArea console) { 
      this.console = console; 
     } 

     public void appendText(String valueOf) { 
      Platform.runLater(() -> console.appendText(valueOf)); 
     } 

     public void write(int b) throws IOException { 
      appendText(String.valueOf((char)b)); 
     } 
    } 
} 

编辑2:看来我的问题是太长,很难理解。我正在重组这个中间。


编辑3

我想我应该只是显示这里的一切。我想要做的是一个CLI应用程序的简单GUI前端。我是CS学生,Java是我们的主要语言,所以这主要是为了练习。


我一直在寻找每个小时和几小时的地方,但仍然没有解决方案。我尝试过像以前一样使用Swing。该方法在Swing中运行良好,但与JavaFX无关。

这是我(目前)logger.java类:

package application; 

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

import javafx.application.Platform; 
import javafx.fxml.Initializable; 
import javafx.scene.control.*; 

public class ytdlLogger extends OutputStream implements Initializable 
{ 
    private TextArea loggerPane; 

    public ytdlLogger(TextArea loggerPane) { 
     this.loggerPane = loggerPane; 
    } 

    public void appendText(String valueOf) { 
     Platform.runLater(() -> loggerPane.appendText(valueOf)); 
    } 

    @Override 
    public void initialize(URL location, ResourceBundle resources) { 
     OutputStream out = new OutputStream() { 
      @Override 
      public void write(int b) throws IOException { 
       appendText(String.valueOf((char)b)); 
      } 
     }; 
     System.setOut(new PrintStream(out, true)); 
     System.setErr(new PrintStream(out, true)); 
    } 

    @Override 
    public void write(int b) throws IOException { 
     // TODO Auto-generated method stub 

    } 
} 

我不认为有任何这方面的实际问题。我也添加了PrintStream对象,将MainController类中的System.setOut和System.setErr重定向到TextArea,但它也不起作用。

我也有另一个主类,这是加载FXML的主要事情。我尝试重定向从那里输出,它几乎工作。差不多,因为我停止在Eclipse内看到控制台输出,我知道这是一个很大的进步。

那么,这里似乎是什么问题?是因为FXML吗?我绝对是Java和JavaFX的初学者,这是我的第一个JavaFX应用程序。任何指导非常感谢。先谢谢你。


编辑1

这里的主要类:

package application; 

import javafx.application.Application; 
import javafx.fxml.FXMLLoader; 
import javafx.stage.Stage; 
import javafx.scene.Parent; 
import javafx.scene.Scene; 

public class Main extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     try { 
      Parent root = FXMLLoader.load(getClass().getResource("/application/Main.fxml")); 
      Scene scene = new Scene(root); 
      primaryStage.setScene(scene); 
      primaryStage.show(); 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+0

有什么异常? – ItachiUchiha

+0

如果文本区域是在场景构建器中创建的,它应该有一个'@FXML'注释。否则它会认为它是一个不同的对象。 –

+0

你可以显示你的'Main'类的代码吗?问题不在于你在记录器中实现了'write(...)'方法吗? –

回答

1

你之前用的console值初始化ps已由FXMLLoader初始化。即你有

@FXML 
private TextArea console; 
private PrintStream ps = new PrintStream(new Console(console)); 

显然console仍然null,当你把它传递给new Console(...)

FXMLLoader已初始化注入的字段,您可以使用initialize方法执行操作后,您需要初始化ps

SSCCE:

MainController.java:

package application; 

import java.io.IOException; 
import java.io.OutputStream; 
import java.io.PrintStream; 

import javafx.application.Platform; 
import javafx.event.ActionEvent; 
import javafx.fxml.FXML; 
import javafx.scene.control.TextArea; 

public class MainController { 

    @FXML 
    private TextArea console; 
    private PrintStream ps ; 

    public void initialize() { 
     ps = new PrintStream(new Console(console)) ; 
    } 

    public void button(ActionEvent event) { 
     System.setOut(ps); 
     System.setErr(ps); 
     System.out.println("Hello World"); 
    } 

    public class Console extends OutputStream { 
     private TextArea console; 

     public Console(TextArea console) { 
      this.console = console; 
     } 

     public void appendText(String valueOf) { 
      Platform.runLater(() -> console.appendText(valueOf)); 
     } 

     public void write(int b) throws IOException { 
      appendText(String.valueOf((char)b)); 
     } 
    } 
} 

Main.java:

package application; 

import javafx.application.Application; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Parent; 
import javafx.scene.Scene; 
import javafx.stage.Stage; 


public class Main extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     try { 
      Parent root = FXMLLoader.load(getClass().getResource("test.fxml")); 
      Scene scene = new Scene(root); 
      primaryStage.setScene(scene); 
      primaryStage.show(); 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

test.fxml:

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.layout.BorderPane?> 
<?import javafx.scene.control.TextArea?> 
<?import javafx.scene.control.Button?> 
<?import javafx.geometry.Insets?> 

<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainController"> 
    <center> 
     <TextArea fx:id="console"/> 
    </center> 
    <bottom> 
     <Button onAction="#button" text="Output"> 
      <BorderPane.alignment>CENTER</BorderPane.alignment> 
      <BorderPane.margin><Insets top="5" left="5" right="5" bottom="5"/></BorderPane.margin> 
     </Button> 
    </bottom> 
</BorderPane> 
+0

非常感谢。这工作得很好。它对我的程序也是非常好的。但是我怎样才能使System.setOut从一开始就被设置,而不仅仅是当按钮被按下时呢?说如果我有几个按钮,是否必须在每种方法中使用'System.setOut'? –

+0

如果您努力停下来思考我的解决方案为什么可行,为什么您的原始代码没有这样做,那么您就不需要问这个问题。停止复制代码并开始尝试理解它在做什么。 –

+0

不,它工作得很好,我没有任何麻烦实施它。我试图记录每一种实现的方法和代码,以便我理解它的作用,这一切都是为了我自己的理解。 –

1

你不与FXMLLoader使用您的控制器。否则你会得到一个异常,因为这个类没有默认的构造函数。

如果你想使用FXMLLoader创建您ytdlLogger,添加属性fx:controller="application.ytdlLogger"(其中fx是FXML命名空间前缀)添加到您FXML文件的根元素。

如果你想做到这一点,还需要改变一些东西:

  • ytdlLogger需要一个默认的构造函数(即要么删除您的构造函数或创建不带参数的一个新的)。

  • @FXML注释添加到您的loggerPane场,让FXMLLoader访问场与fx:id="loggerPane"属性给它分配TextArea

  • 更好地从控制器中删除基类OutputStream,因为您不使用它。
  • 添加一些打印到System.outSystem.err的代码。否则没有什么会写入TextArea。确保在控制器初始化后执行此操作。

你的控制器看起来应该是这样的变化后:

public class ytdlLogger implements Initializable 
{ 

    @FXML 
    private TextArea loggerPane; 

    public void appendText(String valueOf) { 
     Platform.runLater(() -> loggerPane.appendText(valueOf)); 
    } 

    @Override 
    public void initialize(URL location, ResourceBundle resources) { 
     OutputStream out = new OutputStream() { 
      @Override 
      public void write(int b) throws IOException { 
       appendText(String.valueOf((char)b)); 
      } 
     }; 
     System.setOut(new PrintStream(out, true)); 
     System.setErr(new PrintStream(out, true)); 
    } 

} 

而且FXML应该类似于此

<?xml version="1.0" encoding="UTF-8"?> 

<?import java.lang.*?> 
<?import java.util.*?> 
<?import javafx.scene.*?> 
<?import javafx.scene.control.*?> 
<?import javafx.scene.layout.*?> 

<AnchorPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" 
      fx:controller="application.ytdlLogger"> <!-- controller goes here --> 
    <children> 
     <TextArea fx:id="loggerPane" /> <!-- the TextArea you want to use for logging --> 
    </children> 
</AnchorPane> 
+0

我没有在控制器中使用FXMLLoader,而是在加载FXML的Main类中。控制器位于不同的类“MainController”中。在MainController内部是FXML为TextArea和其他文件的'fx:id'找到的地方。 –

+0

我尝试在Main.java类中添加'System.setOut'和'System.setErr',或者甚至在按钮确实是它的实际作业之前,它在其中加载进程。 Eclipse中的控制台变成空白,程序将挂起并耗尽我的资源,而不是无所事事。 –

+0

我想我的问题还不够清楚。我已经包括了一切,所以你可以得到我想要做的。抱歉。 –

相关问题