Ява ученик пытается мигрировать из System.out.println, чтобы качаться - PullRequest
0 голосов
/ 24 ноября 2011

Я наконец пытаюсь перенести свои старые консольные программы на Swing, чтобы облегчить распространение среди моих друзей.С этой целью я пытаюсь написать класс ConsoleFrame, который я могу расширить вместо JFrame, который позволит мне связывать мой старый код с Swing настолько легко, насколько это возможно.out (String), похоже, работает, но inln () поставил меня в тупик.

//Imports not included
public class ConsoleFrame extends JFrame
{
    protected JTextField in;
    protected JTextArea out;

    public ConsoleFrame(){
        this("Console Frame", 80, 10);
    }
    public ConsoleFrame(int cols){
        this("Console Frame", cols, 10);
    }
    public ConsoleFrame(int cols, int rows){
        this("Console Frame", cols, rows);
    }
    public ConsoleFrame(String title){
         this(title, 80, 10);
    }
    public ConsoleFrame(String title, int cols, int rows){
        in = new JTextField();
        in.setEditable(true);
        in.setColumns(cols);

        out = new JTextArea();
        out.setEditable(false);
        out.setColumns(cols);
        out.setRows(rows);
        out.setWrapStyleWord(true);

        setTitle(title);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        add(in, BorderLayout.PAGE_END);
        add(out, BorderLayout.PAGE_START);
        pack();
    }

    protected void out(String o) {
        out.append(o);
    }
    protected void outln(String o) {
            out(o + BIO.$ln);    //BIO.$ln == System.getProperty("line.separator")
    }

    /*
     * This is supposed to halt execution until the user presses enter, then return the text entered in the JTextField named in.
     */
    protected String inln() {
        in.setEnabled(true);
        KeyListener enter = new KeyListener() {
            @Override
            public void keyTyped(KeyEvent paramKeyEvent) {
                if(paramKeyEvent.getKeyCode() == KeyEvent.VK_ENTER) {
                     if(in.hasFocus()) {
                         in.setEnabled(false);
                     }
                }
            }
            @Override public void keyPressed(KeyEvent paramKeyEvent) {}
            @Override public void keyReleased(KeyEvent paramKeyEvent) {}    
        };
        in.addKeyListener(enter);
        while(true){    //This loop is intended to interrupt flow until in.isEnabled()==false, which will only happen when the enter key is typed.
            if(in.isEnabled()==false){
                String result = in.getText();
                in.setText("");
                in.setCaretPosition(0);
                this.removeKeyListener(enter);
                in.setEnabled(true);
                return result;
            }
        }
    }
}

Программа тестирования:

public class Tester extends ConsoleFrame
{
    public static void main(String[] args) {
        new Tester();
    }
    public Tester() {
        super("Test", 60, 30);
        out(inln());
    }
}

Ответы [ 4 ]

2 голосов
/ 24 ноября 2011

Не знаю, решит ли это вашу проблему, но вам НЕ следует использовать KeyListner.

JTextField был разработан для использования ActionListener для обработки клавиши Enter.

1 голос
/ 24 ноября 2011

Немного отладки показывает, что код ключа всегда 0x0.Замена keyTyped на следующий код, кажется, работает;

public void keyTyped(KeyEvent paramKeyEvent) {
    if (paramKeyEvent.getKeyChar() == '\n') {
        if(in.hasFocus()) {
            in.setEnabled(false);
        }
    }
}

РЕДАКТИРОВАТЬ: Я не говорю, что это решение, которое я слишком доволен, но, похоже, это делаеттрюк.

0 голосов
/ 25 ноября 2011

Этот inln код выглядит для меня неестественно.Чтобы сделать его более надежным:

  • Измените свой код так, чтобы фактическая программа выполнялась в потоке, отличном от потока диспетчеризации событий (я не уверен, что это уже так).SwingUtilities.isEventDispatchThread должен возвращать false при вызове из тестовой программы.

  • Использовать SwingUtilities.invokeLater в ваших методах вывода, чтобы фактический вывод происходил в потоке диспетчеризации событий асинхронно.

  • в inln(), используйте синхронизацию и SwingUtilities.invokeAndWait для инициализации вашего ключевого слушателя (или используйте ActionListener, как уже было сказано).Затем используйте Object.wait() и Object.notify() вместо цикла ожидания занятости во время ожидания ввода (батареи пользователей ноутбука будут благодарны вам за это, а также диспетчер задач, который больше не будет отображать 100% загрузку ЦП).


Извините, вот (проверенный и работающий) код для вас:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ConsoleFrame extends JFrame
{
    private Object lock = new Object();
    private String enteredText = null;

    protected JTextField in;
    protected JTextArea out;

    public ConsoleFrame(){
        this("Console Frame", 80, 10);
    }
    public ConsoleFrame(int cols){
        this("Console Frame", cols, 10);
    }
    public ConsoleFrame(int cols, int rows){
        this("Console Frame", cols, rows);
    }
    public ConsoleFrame(String title){
         this(title, 80, 10);
    }
    public ConsoleFrame(String title, int cols, int rows){
        in = new JTextField();
        in.setEditable(true);
        in.setColumns(cols);

        ActionListener enter = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                in.setEnabled(false);
                synchronized(lock) {
                    enteredText = in.getText();
                    lock.notifyAll();
                }
                in.setText("");
            }
        };
        in.addActionListener(enter);

        out = new JTextArea();
        out.setEditable(false);
        out.setColumns(cols);
        out.setRows(rows);
        out.setWrapStyleWord(true);

        setTitle(title);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        add(in, BorderLayout.PAGE_END);
        add(out, BorderLayout.PAGE_START);
        pack();
    }

    protected void out(final String o) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                out.append(o);
            }
        });
    }

    protected void outln(String o) {
            out(o + System.getProperty("line.separator"));
    }

    /*
     * This is supposed to halt execution until the user presses enter, then return the text entered in the JTextField named in.
     */
    protected String inln() {
        SwingUtilities.invokeLater(new Runnable() { 
            @Override
            public void run() {
                in.setEnabled(true);
            }
        });
        synchronized(lock) {
            enteredText = null;
            while (enteredText == null) {
                try {
                    lock.wait();
                } catch (InterruptedException ex) {}
            }
            return enteredText;
        }
    }
}
0 голосов
/ 24 ноября 2011

Вы добавляете keyListener к фрейму, а не текстовое поле in.Поэтому событие всегда будет захвачено текстовым полем и никогда не будет распространяться до кадра.Вот почему вы не получаете событие.

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