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

时间:2016-12-21 16:23:46

标签: java shell javafx system.in

我正在研究新项目。我试图通过以太网从Java发送命令到外部计算机(Linux)。我正在使用Jsch来创建shell连接。我将shell输入和输出设置为System.out和System.in。

((ChannelShell)channel).setInputStream(System.in);
((ChannelShell)channel).setOutputStream(System.out);

它适用于控制台!但我需要从javafx GUI应用程序远程访问它。我已经解决了将System.out重定向到TextArea的问题:

    public void redirectOutputStream() {
        OutputStream out = new OutputStream() {

            private final StringBuilder sb = new StringBuilder();

            @Override
            public void write(int b) throws IOException {
                if (b == '\r') {
                    return;
                }

                if (b == '\n') {
                    final String tmp = sb.toString() + "\n";
                    text.add(tmp);
                    updateText(text);
                    sb.setLength(0);
                } else {
                    sb.append((char) b);
                }
            }
        };

        System.setOut(new PrintStream(out, true));
        // System.setErr(new PrintStream(out, true));
    }

但现在我还需要将System.in重定向到TextField,以便我可以在TextField中写入内容,按回车并通过shell将其发送到外部计算机。

任何帮助都会受到赞赏。谢谢!

修改 对不起,仍然不适合我:( ... 现在我有了这段代码(我使用的是javafx):

/** Tmp queue for standard input redirecting */
BlockingQueue<Integer> stdInQueue = new LinkedBlockingQueue<>();



 @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        redirectOutputStream();
        redirectInputStream();
}


/** redirects standard System.out to GUI command_window */
public void redirectOutputStream() {
    OutputStream out = new OutputStream() {

        private final StringBuilder sb = new StringBuilder();

        @Override
        public void write(int b) throws IOException {
            if (b == '\r') {
                return;
            }
            if (b == '\n') {
                final String tmp = sb.toString() + "\n";
                text.add(tmp);
                updateText(text);
                sb.setLength(0);
            } else {
                sb.append((char) b);
            }
        }
    };
    System.setOut(new PrintStream(out, true));
    System.setErr(new PrintStream(out, true));
}

/** redirects standard System.in to GUI command_line */
public void redirectInputStream() {
    InputStream in = new InputStream() {

        @Override
        public int read() throws IOException {
            try {
                int c = stdInQueue.take().intValue();
                return c;
            } catch (InterruptedException exc) {
                Thread.currentThread().interrupt();
                return -1;
            }
        }
    };
    System.setIn(in);
}


@FXML
    void sendButtonPressed(ActionEvent event) {
        if (!command_line.getText().isEmpty()) {
            for (char c : command_line.getText().toCharArray()) {
                System.out.write(new Integer(c)); //display in ListView (output)
                stdInQueue.add(new Integer(c)); 
            }
            System.out.write(new Integer('\n')); //display in ListView (output)     
            stdInQueue.add(new Integer('\n'));
            command_line.clear();
        }
    }

System.out和System.err的重定向工作完美。它显示在javafx ListView中。

问题仍然是在ListView下我有一个“命令行”javafx TextField我需要在这个TextField中编写一些ssh命令,并在按下“enter”或点击“send”按钮时将其重定向到System.in

我需要这样做的原因是我正在使用为System.in和System.out设置的SSH通信。它完全适用于控制台(已测试),但不适用于我的GUI应用程序。

感谢您提供进一步的建议!

2 个答案:

答案 0 :(得分:0)

您可以设置BlockingQueue<Integer>发送单个字符,然后让输入流从中获取字符:

BlockingQueue<Integer> stdInQueue = new LinkedBlockingQueue<>();

System.setIn(new InputStream() {

    @Override
    public int read() throws IOException {
        try {
            int c = stdInQueue.take().intValue();
            return c;
        } catch (InterruptedException exc) {
            Thread.currentThread().interrupt();
            return -1 ;
        }
    }
});

textField.setOnAction(e -> {
    for (char c : textField.getText().toCharArray()) {
        stdInQueue.add(new Integer(c));
    }
    stdInQueue.add(new Integer('\n'));
    textField.clear();
});

这是一个快速演示:对于测试我只是设置了一个从System.in读取的后台线程:

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class StdInFromTextField extends Application {

    @Override
    public void start(Stage primaryStage) {

        TextField textField = new TextField();

        BlockingQueue<Integer> stdInQueue = new LinkedBlockingQueue<>();

        System.setIn(new InputStream() {

            @Override
            public int read() throws IOException {
                try {
                    int c = stdInQueue.take().intValue();
                    return c;
                } catch (InterruptedException exc) {
                    Thread.currentThread().interrupt();
                    return -1 ;
                }
            }
        });

        textField.setOnAction(e -> {
            for (char c : textField.getText().toCharArray()) {
                stdInQueue.add(new Integer(c));
            }
            stdInQueue.add(new Integer('\n'));
            textField.clear();
        });

        // for testing:
        Thread readThread = new Thread(() -> {
            try {
                int i ;
                while ((i = System.in.read()) != -1) {
                    System.out.print((char)i);
                }
            } catch (IOException exc) {
                exc.printStackTrace();
            }
        });
        readThread.setDaemon(true);
        readThread.start();

        primaryStage.setScene(new Scene(new StackPane(textField), 300, 120));
        primaryStage.show();
    }

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

答案 1 :(得分:0)

好的,我现在有工作代码。问题是,我没弄明白,如何重定向System.in(这可能是不可能的)。所以我不得不直接从SSH连接器重定向流。

以下是我在jsch流中设置输入和输出的方法:

public class ToradexSSHCommunicator {

String user;
String password;
String ip;
int port;

InputStream fromChannel;
OutputStream toChannel;

/** logger for error output feed */
private static final Logger LOGGER = Logger.getLogger(ToradexSSHCommunicator.class);

public ToradexSSHCommunicator(String user, String password, String ip, int port) {
    this.user = user;
    this.password = password;
    this.ip = ip;
    this.port = port;
}

public void startup() {
    Session session = null;
    ChannelShell channel = null;
    boolean isConnected = false;

    JSch jsch = new JSch();
    while (!isConnected) {
        try {
            session = jsch.getSession(user, ip, port);

            session.setPassword(password);
            session.setConfig("StrictHostKeyChecking", "no");

            LOGGER.info("Establishing Toradex Connection...");
            session.setTimeout(1000);
            session.connect();
            LOGGER.info("Toradex connection established.");

            LOGGER.info("Creating Toradex channel...");
            channel = (ChannelShell) session.openChannel("shell");
            LOGGER.info("Toradex channel created.");

            fromChannel = channel.getInputStream();
            toChannel = channel.getOutputStream();

            channel.connect();
            isConnected = true;

        }
        catch (JSchException e) {
            LOGGER.error("Toradex connection error.....RECONNECTING", e);
            session.disconnect();
        }
        catch (IOException e) {
            LOGGER.error("Toradex connection error.....RECONNECTING", e);
            session.disconnect();
        }
    }

}

public InputStream getFromChannel() {
    return fromChannel;
}

public OutputStream getToChannel() {
    return toChannel;
    }
}

使用此流的GUI部分:

@FXML
private ListView<String> command_window_toradex;
@FXML
private TextField command_line;

private ToradexSSHCommunicator comm;

private BufferedReader br;
private BufferedWriter bw;

@FXML
    void sendButtonPressed(ActionEvent event) {
        executor.submit(new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                writeCommand();
                return null;
            }
        });
    }

/** initialize SSH connection to Toradex and redirect input and output streams to GUI */
private void initToradex() {
    comm = new ToradexSSHCommunicator(GuiConstants.TORADEX_USER, GuiConstants.TORADEX_PASSWORD,
            GuiConstants.TORADEX_IP_ADDRESS, GuiConstants.TORADEX_PORT);
    comm.startup();
    br = new BufferedReader(new InputStreamReader(comm.getFromChannel()));
    bw = new BufferedWriter(new OutputStreamWriter(comm.getToChannel()));
}

private void writeCommand() throws IOException {
    if (!command_line.getText().isEmpty()) {
        String command = command_line.getText();
        bw.write(command + '\n');
        bw.flush();
        command_line.clear();
    }
}

private void readCommand() throws IOException {
    String commandLine = null;
    while (true) {
        commandLine = br.readLine();
        textToradex.add(commandLine);
    }
}

有效!但是现在这是整个代码,如果您需要任何进一步的帮助,请问。