Redirect System.in to swing component

只谈情不闲聊 提交于 2019-12-12 07:23:57

问题


Hey guys I am making a terminal application using Swing and Apache Commons. I was able to redirect System.out and System.err to a JTextArea easily but how do I do that for System.in ? Will I need to override Inputstream methods? Do I need to convert the String from JTextArea to byte array and then pass it to InputStream? Code examples would be nice.


回答1:


I recently tried the same thing, here's my code:

class TexfFieldStreamer extends InputStream implements ActionListener {

    private JTextField tf;
    private String str = null;
    private int pos = 0;

    public TexfFieldStreamer(JTextField jtf) {
        tf = jtf;
    }

    //gets triggered everytime that "Enter" is pressed on the textfield
    @Override
    public void actionPerformed(ActionEvent e) {
        str = tf.getText() + "\n";
        pos = 0;
        tf.setText("");
        synchronized (this) {
            //maybe this should only notify() as multiple threads may
            //be waiting for input and they would now race for input
            this.notifyAll();
        }
    }

    @Override
    public int read() {
        //test if the available input has reached its end
        //and the EOS should be returned 
        if(str != null && pos == str.length()){
            str =null;
            //this is supposed to return -1 on "end of stream"
            //but I'm having a hard time locating the constant
            return java.io.StreamTokenizer.TT_EOF;
        }
        //no input available, block until more is available because that's
        //the behavior specified in the Javadocs
        while (str == null || pos >= str.length()) {
            try {
                //according to the docs read() should block until new input is available
                synchronized (this) {
                    this.wait();
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
        //read an additional character, return it and increment the index
        return str.charAt(pos++);
    }
}

and use it like this:

    JTextField tf = new JTextField();
    TextFieldStreamer ts = new TextFieldStreamer(tf);
    //maybe this next line should be done in the TextFieldStreamer ctor
    //but that would cause a "leak a this from the ctor" warning
    tf.addActionListener(ts);

    System.setIn(ts);

Has been a while since I coded Java so I may not be up-to-date with the patterns. You should probably also overload int available() but my example just consists of the bare minimum to make it work with a BufferedReaders readLine() function.

Edit: For this to work for a JTextField you have to use implements KeyListener instead of implements ActionListener and then use addKeyListener(...) on your TextArea. The function that you need instead of actionPerformed(...) is public void keyPressed(KeyEvent e) and then you have to test for if (e.getKeyCode() == e.VK_ENTER) and instead of using the whole text you just use a substring from the last line before the cursor with

//ignores the special case of an empty line
//so a test for \n before the Caret or the Caret still being at 0 is necessary
int endpos = tf.getCaret().getMark();
int startpos = tf.getText().substring(0, endpos-1).lastIndexOf('\n')+1;

for the input string. Because otherwise you would read the whole TextArea every time you press enter.




回答2:


You need to create your own implementation of an InputStream that takes its input from whatever Swing component you want… basically have a buffer that you copy text to from your Swing component and that serves as a source for the InputStream (which of course needs to block if no input is available).



来源:https://stackoverflow.com/questions/9244108/redirect-system-in-to-swing-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!