Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
146 views
in Technique[技术] by (71.8m points)

java - System.in points to JtextArea and using Scanner with it causes application to hang

I've got a JFrame that contains a single JPanel that contains a single JTextArea. I've successfully managed to point System.out to the JTextArea, but when I try to use Scanner(System.in) to parse input from the JTextArea, it doesn't even seem to load anything. As in, when I build and run the application, nothing happens, no frame is presented. Here is my code:

/**
 * Create the frame.
 */
public TerminalForm() {
    setTitle("Terminal");
    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    setBounds(100, 100, 570, 370);
    contentPane = new JPanel();
    contentPane.setBorder(BorderFactory.createEmptyBorder());
    setContentPane(contentPane);
    contentPane.setLayout(new BorderLayout(0, 0));

    PipedInputStream inPipe = new PipedInputStream();
    PipedInputStream outPipe = new PipedInputStream();

    System.setIn(inPipe);
    try {
        System.setOut(new PrintStream(new PipedOutputStream(outPipe), true));
    } catch (IOException e1) {
        e1.printStackTrace();
    }
    PrintWriter inWriter = null;
    try {
        inWriter = new PrintWriter(new PipedOutputStream(inPipe), true);
    } catch (IOException e) {
        e.printStackTrace();
    }

    final JTextArea txtIO = console(outPipe, inWriter);
    txtIO.setFont(new Font("Andale Mono", Font.PLAIN, 12));
    txtIO.setCaretColor(new Color(50, 205, 50));
    txtIO.getCaret().setVisible(true);
    txtIO.getCaret().setSelectionVisible(true);
    txtIO.setLineWrap(true);
    txtIO.setForeground(new Color(50, 205, 50));
    txtIO.setBackground(new Color(0, 0, 0));
    txtIO.setBorder(BorderFactory.createEmptyBorder());
    contentPane.add(txtIO);

    // 5. get some input (from JTextArea)
    Scanner s = new Scanner(System.in);
    System.out.printf("got from input: "%s"%n", s.nextLine());
}

public static JTextArea console(final InputStream out, final PrintWriter in) {
    final JTextArea area = new JTextArea();

    // handle "System.out"
    new SwingWorker<Void, String>() {
        @Override protected Void doInBackground() throws Exception {
            Scanner s = new Scanner(out);
            while (s.hasNextLine()) publish(s.nextLine() + "
");
            s.close();
            return null;
        }
        @Override protected void process(List<String> chunks) {
            for (String line : chunks) area.append(line);
        }
    }.execute();

    // handle "System.in"
    area.addKeyListener(new KeyAdapter() {
        private StringBuffer line = new StringBuffer();
        @Override public void keyTyped(KeyEvent e) {
            char c = e.getKeyChar();
            if (c == KeyEvent.VK_ENTER) {
                in.println(line);
                line.setLength(0); 
            } else if (c == KeyEvent.VK_BACK_SPACE) { 
                line.setLength(line.length() - 1); 
            } else if (!Character.isISOControl(c)) {
                line.append(e.getKeyChar());
            }
        }
    });

    return area;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If this were my code, I'd not have the user type directly into the JTextArea, but rather in a JTextField that is directly below the JTextArea (BorderLayout.SOUTH to the JTextArea which is held in a JScrollPane that is BorderLayout.CENTER). I'd then accept input via enter, via an ActionListener, and then print what the user enters into the JTextArea with some indication that it's from the user, and also send the entered text out via the OutputStream, or better a PrintStream.

For example, something like,

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.List;
import java.util.Scanner;

import javax.swing.*;
import javax.swing.text.JTextComponent;

@SuppressWarnings("serial")
public class TerminalForm extends JPanel {
   private static final int GAP = 3;
   public static final String PRE_TEXT = "User> ";
   private JTextArea textarea;
   private JTextField textfield;

   public TerminalForm(int rows, int cols, InputStream inStream, PrintStream printStream) {
      textarea = prepareTextArea(rows, cols, inStream);
      textfield = prepareTextField(cols, printStream, textarea);

      setLayout(new BorderLayout(GAP, GAP));
      setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
      add(new JScrollPane(textarea), BorderLayout.CENTER);
      add(textfield, BorderLayout.SOUTH);
   }

   private JTextField prepareTextField(int cols, PrintStream printStream, JTextArea textArea) {
      JTextField textField = new JTextField(cols);
      textField.addActionListener(new TextFieldListener(printStream, textArea));
      return textField;
   }

   private JTextArea prepareTextArea(int rows, int cols, InputStream inStream) {
      JTextArea textArea = new JTextArea(rows, cols);
      textArea.setEditable(false);
      textArea.setFocusable(false);
      InputStreamWorker instreamWorker = new InputStreamWorker(textArea, inStream);
      instreamWorker.execute();
      return textArea;
   }

   private class TextFieldListener implements ActionListener {
      private PrintStream printStream;
      private JTextArea textArea;

      public TextFieldListener(PrintStream printStream, JTextArea textArea) {
         this.printStream = printStream;
         this.textArea = textArea;
      }

      @Override
      public void actionPerformed(ActionEvent evt) {
         JTextComponent textComponent = (JTextComponent) evt.getSource();
         String text = textComponent.getText();
         textComponent.setText("");

         printStream.println(text);
         textArea.append(TerminalForm.PRE_TEXT + text + "
");
      }
   }

   private class InputStreamWorker extends SwingWorker<Void, String> {
      private Scanner scanner;
      private JTextArea textArea;

      private InputStreamWorker(JTextArea textArea, InputStream inStream) {
         this.textArea = textArea;
         scanner = new Scanner(inStream);
      }

      @Override
      protected Void doInBackground() throws Exception {
         while (scanner.hasNextLine()) {
            publish(scanner.nextLine());
         }
         return null;
      }

      @Override
      protected void process(List<String> chunks) {
         for (String chunk : chunks) {
            textArea.append(chunk + "
");
         }
      }
   }

   private static void createAndShowGui(final InputStream inStream, final PrintStream printStream) {
      int rows = 20;
      int cols = 40;
      TerminalForm mainPanel = new TerminalForm(rows, cols, inStream, printStream);

      JFrame frame = new JFrame("TerminalForm2");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      final InputStream inStream = System.in;
      final PrintStream printStream = System.out;
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui(inStream, printStream);
         }
      });
   }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...