You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将System.in重定向至JavaFX TextField?

JavaFX控制台GUI输入重定向问题:ConsoleTask移至Controller后无法运行

我是Java/JavaFX新手,正在开发控制台GUI应用,遇到无法将System.in重定向到JavaFX TextField的问题,尝试过两种方案均未成功。后续找到基于FXML的可行方案,代码参考自Slaws的回答,但目前出现新问题:ConsoleTask放在Controller类中无法运行,此前在Main类中可正常运行,期望实现用GUI的TextField作为Java控制台程序的输入。


已实现的基础FXML方案

该代码适配FXML文件,其余逻辑参考自Slaws的回答。

Main.java

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
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 {

    final static ExecutorService threadPool = Executors.newFixedThreadPool(3, r -> {
        var t = new Thread(r);
        t.setDaemon(true);
        return t;
    });

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

    @Override
    public void start(Stage stage) throws Exception {

        Parent root = FXMLLoader.load(getClass().getResource("mainScreen.fxml"));
        String css = this.getClass().getResource("style.css").toExternalForm();
        Scene scene = new Scene(root);
        scene.getStylesheets().add(css);
        stage.setMinHeight(800);
        stage.setMinWidth(1200);
        stage.setScene(scene);
        stage.show();
        
    }

    @Override
    public void stop() {
        threadPool.shutdownNow();
    }
}

Controller.java

import java.io.IOException;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.text.Font;
import javafx.application.Platform;

public class Controller {
    
    @FXML
    private TextArea console;
    @FXML
    private TextField inputPane;
    
    public void initialize() throws IOException{

        wireInputAndOutput(inputPane, console);
        startConsoleTask();

    }

    static void wireInputAndOutput(TextField input, TextArea output) throws IOException {
        var inputConsumer = StreamWriter.redirectStandardIn(Main.threadPool);
        StreamReader.redirectStandardOut(new BufferedTextAreaAppender(output), Main.threadPool);

        input.setOnAction(e -> {
            e.consume();
            var text = input.textProperty().getValueSafe() + "\n";
            output.appendText(text);
            inputConsumer.accept(text);
            input.clear();
        });
    }
    private void startConsoleTask() {
        Main.threadPool.execute(new ConsoleTask(Platform::exit));
    }
}

编辑补充:当前核心问题

将ConsoleTask移到Controller.java后无法运行,此前直接复制Slaws的Main.java代码时可正常运行,但为适配FXML改造后功能失效。

test.fxml

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.VBox?>


<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="700.0" prefWidth="800.0" style="-fx-background-color: white;" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller">
   <children>
      <TextArea fx:id="console" editable="false" prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS">
         <VBox.margin>
            <Insets bottom="20.0" />
         </VBox.margin>
      </TextArea>
      <TextField fx:id="inputPane" prefHeight="40.0" VBox.vgrow="ALWAYS" />
   </children>
   <padding>
      <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
   </padding>
</VBox>

ConsoleTask.java

import java.util.NoSuchElementException;
import java.util.Scanner;

class ConsoleTask implements Runnable {

    private final static Scanner scanner = new Scanner(System.in);
    private final Runnable onExit;

    ConsoleTask(Runnable onExit) {
        this.onExit = onExit;
    }

    @Override
    public void run() {
        System.out.println("WELCOME TO CONSOLE APP!");

        boolean running = true;
        while (running && !Thread.interrupted()) {
            printOptions();

            int choice = readInt("Choose option: ", 1, 20);
            switch (choice) {
                case 1 -> doCheckIfLeapYear();
                case 2 -> doCheckIfPrime();
                case 3 -> doPrintStringBackwards();
                case 20 -> running = false;
                default -> System.out.println("Unknown option!");
            }
            
            System.out.println("\nPlease wait...");
            wait(6000);
        }
        
        onExit.run();
    }

    private void printOptions() {
        System.out.println();
        System.out.println("Options");
        System.out.println("-------");
        System.out.println("  1) Test Leap Year");
        System.out.println("  2) Test Prime");
        System.out.println("  3) Print String backwards");
        System.out.println("  20) Exit");
        System.out.println();
    }

    private int readInt(String prompt, int min, int max) {
        while (true) {
            System.out.print(prompt);

            try {
                int i = Integer.parseInt(scanner.nextLine());
                if (i >= min && i <= max) {
                    return i;
                }
            } catch (NumberFormatException | NoSuchElementException ignored) {
            }
            System.out.printf("Please enter an integer between [%,d, %,d]%n", min, max);
        }
    }

    private void doCheckIfLeapYear() {
        System.out.println();
        int year = readInt("Enter year: ", 0, 1_000_000);
        if (year % 4 == 0 || (year % 100 == 0 && year % 400 != 0)) {
            System.out.printf("The year %d is a leap year.%n", year);
        } else {
            System.out.printf("The year %d is NOT a leap year.%n", year);
        }
    }

    private void doCheckIfPrime() {
        System.out.println();
        int limit = readInt("Enter an Integer: ", 1, Integer.MAX_VALUE);

        while (limit <= 1){
            System.out.print("Wrong number! the number should be higher or equal to 2: ");
            limit = scanner.nextInt();
        }

        if(isPrime(limit)){
            System.out.println(limit+" is a prime number.");
        }else{
            System.out.println(limit+" is not a prime number.");
        }
    }
    private static boolean isPrime(int n){
        if(n <= 1){
            return false;
        }
        for(int i = 2; i <= Math.sqrt(n); i++){
            if(n % i == 0){
            return false;
            }
        }
        return true;   
    }

    private static void doPrintStringBackwards(){
        System.out.println();
        System.out.print("\nEnter a word or a sentence: ");
        String answer = scanner.nextLine();

        //StackOverflow version: (simple) 
        System.out.println("\n"+new StringBuilder(answer).reverse().toString());
        
        //Lecture version:
        /*for (int i = answer.length()-1;i>=0;i--){
            System.out.print(answer.charAt(i));
        }*/
    }
    private static void wait(int ms){
        try {
            Thread.sleep(ms);
        }
        catch(InterruptedException ex) {
            Thread.currentThread().interrupt();
        }
    }
}

内容的提问来源于stack exchange,提问作者UnseenSnick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 14:15:36