Redirect System.in to swing component

后端 未结 2 1528
礼貌的吻别
礼貌的吻别 2021-01-07 07:27

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

2条回答
  •  生来不讨喜
    2021-01-07 07:56

    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.

提交回复
热议问题