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.
2 Answers
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 BufferedReader
s 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.

- 7,981
- 1
- 26
- 34
-
Cool Ill just have to change it so it takes last line of JTextArea. Thanks a lot – Giannis Feb 11 '12 at 21:51
-
@latusaki well, not quite you'd have to modify it a little more, since the `JTextArea` doesn't generate `ActionEvent`s afaik. You could either make an unrelated button and add the action listener to that or override the `JTextArea` and catch the key-events to look out for `Ctrl-Enter` or something similar and then trigger the `ActionEvent` yourself. – PeterT Feb 11 '12 at 21:58
-
read method is not getting called for some reason while testing with textfield. – Giannis Feb 11 '12 at 22:36
-
@latusaki the `read()` is only supposed to be called when someone actually calls `System.in.read()` or if you wrap it in a `new BufferedReader(new InputStreamReader(System.in))` and call `readLine()` it doesn't get called by itself and why would it? – PeterT Feb 11 '12 at 22:50
-
I am still experimenting but what I want is when hitting enter the text goes to InputStream as it would on terminal – Giannis Feb 11 '12 at 22:52
-
@latusaki well if you use System.in then you can only enter something when the program actually calls read() otherwise it stores it in a buffer which is the TextArea in your case. Also, I already told you that the `JTextArea` does not generate an ActionEvent upon pressing enter therefore my code won't work with a `JTextArea` as is. edit: My bad, I mean `JTextArea` of course – PeterT Feb 11 '12 at 23:11
-
let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/7569/discussion-between-latusaki-and-petert) – Giannis Feb 11 '12 at 23:43
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).

- 81,643
- 20
- 123
- 127