JavaFX:将控制台输出重定向到在 SceneBuilder 中创建的 TextArea

Wak*_*age 5 java console textarea javafx scenebuilder

编辑 4

我已经创建了一个简单的示例,它应该可以让您了解当前正在发生的事情。

现在发生的事情是,每当我单击按钮将“HELLO WORLD”打印到 TextArea 时,程序都会挂起并使用 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑 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

    }
}
Run Code Online (Sandbox Code Playgroud)

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

我还有另一个 Main 类,它是加载 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Jam*_*s_D 6

您正在使用 初始化之前ps的值进行初始化。即你有consoleFXMLLoader

@FXML
private TextArea console;
private PrintStream ps = new PrintStream(new Console(console));
Run Code Online (Sandbox Code Playgroud)

当你将它传递给 时显然console是静止的。nullnew Console(...)

您需要在初始化注入的字段ps后进行初始化FXMLLoader,您可以使用该initialize方法来完成此操作。

SSCCE:

主控制器.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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

主要.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);
    }
}
Run Code Online (Sandbox Code Playgroud)

测试.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>
Run Code Online (Sandbox Code Playgroud)