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

戏子无情 提交于 2019-12-14 03:26:48

问题


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() + "\n");
            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;
}

回答1:


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

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

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



回答2:


you didn't set the frame visible.



来源:https://stackoverflow.com/questions/18418257/system-in-points-to-jtextarea-and-using-scanner-with-it-causes-application-to-ha

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!