Перенаправить System.in на компонент Swing - PullRequest
1 голос
/ 12 февраля 2012

Эй, ребята, я делаю терминальное приложение, используя Swing и Apache Commons. Я смог легко перенаправить System.out и System.err на JTextArea, но как мне это сделать для System.in? Нужно ли переопределять Inputstream методы? Нужно ли преобразовывать String из JTextArea в байтовый массив, а затем передавать его в InputStream? Примеры кода были бы хорошими.

Ответы [ 2 ]

4 голосов
/ 12 февраля 2012

Я недавно попробовал то же самое, вот мой код:

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++);
    }
}

и используйте его так:

    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);

Прошло много времени с тех пор, как я закодировал Java, так что я, возможно, не в курсе паттернов. Вероятно, вам также следует перегрузить int available(), но мой пример состоит только из минимума, чтобы заставить его работать с BufferedReader s readLine() функцией.

Редактировать: Чтобы это работало для JTextField, вы должны использовать implements KeyListener вместо implements ActionListener, а затем использовать addKeyListener(...) в вашей TextArea. Нужная вам функция вместо actionPerformed(...) - это public void keyPressed(KeyEvent e), и затем вам нужно проверить на if (e.getKeyCode() == e.VK_ENTER), и вместо использования всего текста вы просто используете подстроку из последней строки перед курсором с

//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;

для входной строки. Потому что в противном случае вы будете читать всю TextArea каждый раз, когда нажимаете ввод.

1 голос
/ 12 февраля 2012

Вам необходимо создать собственную реализацию InputStream, которая получает данные от любого компонента Swing, который вы хотите ... в основном, имеет буфер, в который вы копируете текст из компонента Swing, и который служит источником для InputStream(который, конечно, нужно заблокировать, если нет доступных данных).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...