jTextArea as IO console

自作多情 提交于 2019-12-28 02:19:04

问题


How do I send the input of the user, user input only, to the outputstream?

I'm currently using a keylistner,

jTextArea console = new jTextArea;
console.addKeyListener(new java.awt.event.KeyAdapter() {
        public void keyReleased(java.awt.event.KeyEvent e){
            //save the last lines for console to variable input
            if(e.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER){

                try {
                    int line = console.getLineCount() -2;
                    int start = console.getLineStartOffset(line);
                    int end = console.getLineEndOffset(line);
                    input = console.getText(start, end  - start);
                    send = true;
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
    });`

As you can see, when the user presses the Enter key, the entire last line of the console, textarea.

What I want to happen is, send only the user inputs, not the entire last line. Any help would be greatly appreciated.


回答1:


Okay, so this is my idea...

The basic idea is we want to keep track of "user" input and "process" output.

Basically what I've done is set it up so that when the process terminates, we calculate the current position of the caret in the document and mark that as the start position of the user input.

This example doesn't include writing output to the process, you can slide that in ;)

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.BadLocationException;
import org.w3c.dom.ls.LSException;

public class QuickTerminal {

    public static void main(String[] args) {
        new QuickTerminal();
    }

    public QuickTerminal() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new ConsolePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public interface CommandListener {

        public void commandOutput(String text);

        public void commandCompleted(String cmd, int result);

        public void commandFailed(Exception exp);

    }

    public class ConsolePane extends JPanel implements CommandListener {

        private JTextArea textArea;
        private int userInputStart = 0;
        private Command cmd;

        public ConsolePane() {

            cmd = new Command(this);

            setLayout(new BorderLayout());
            textArea = new JTextArea(20, 30);
            add(new JScrollPane(textArea));

            textArea.addKeyListener(new KeyAdapter() {
                @Override
                public void keyPressed(KeyEvent e) {
                    if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                        int range = textArea.getCaretPosition() - userInputStart;
                        try {
                            String text = textArea.getText(userInputStart, range).trim();
                            System.out.println("[" + text + "]");
                            userInputStart += range;
                            if (!cmd.isRunning()) {
                                cmd.execute(text);
                            } else {
                            }
                        } catch (BadLocationException ex) {
                            Logger.getLogger(QuickTerminal.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    } else {
//                        if (!cmd.isRunning()) {
//                            cmd.send(...);
//                        }
                    }
                }

            });
        }

        @Override
        public void commandOutput(String text) {
            SwingUtilities.invokeLater(new AppendTask(textArea, text));
        }

        @Override
        public void commandFailed(Exception exp) {
            SwingUtilities.invokeLater(new AppendTask(textArea, "Command failed - " + exp.getMessage()));
        }

        @Override
        public void commandCompleted(String cmd, int result) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    int pos = textArea.getCaretPosition();

                    System.out.println("pos = " + pos + "; length = " + textArea.getText().length());

                    textArea.setCaretPosition(textArea.getText().length());
                    userInputStart = pos;
                }
            });
        }

    }

    public class AppendTask implements Runnable {

        private JTextArea textArea;
        private String text;

        public AppendTask(JTextArea textArea, String text) {
            this.textArea = textArea;
            this.text = text;
        }

        @Override
        public void run() {
            textArea.append(text);
        }

    }

    public class Command {

        private CommandListener listener;

        private ProcessRunner runner;

        public Command(CommandListener listener) {
            this.listener = listener;
        }

        public boolean isRunning() {

            return runner != null && runner.isAlive();

        }

        public void execute(String cmd) {

            if (!cmd.trim().isEmpty()) {


                List<String> values = new ArrayList<>(25);
                if (cmd.contains("\"")) {

                    while (cmd.contains("\"")) {

                        String start = cmd.substring(0, cmd.indexOf("\""));
                        cmd = cmd.substring(start.length());
                        String quote = cmd.substring(cmd.indexOf("\"") + 1);
                        cmd = cmd.substring(cmd.indexOf("\"") + 1);
                        quote = quote.substring(0, cmd.indexOf("\""));
                        cmd = cmd.substring(cmd.indexOf("\"") + 1);

                        if (!start.trim().isEmpty()) {
                            String parts[] = start.trim().split(" ");
                            values.addAll(Arrays.asList(parts));
                        }
                        values.add(quote.trim());

                    }

                    if (!cmd.trim().isEmpty()) {
                        String parts[] = cmd.trim().split(" ");
                        values.addAll(Arrays.asList(parts));
                    }

                    for (String value : values) {
                        System.out.println("[" + value + "]");
                    }

                } else {

                    if (!cmd.trim().isEmpty()) {
                        String parts[] = cmd.trim().split(" ");
                        values.addAll(Arrays.asList(parts));
                    }

                }

                runner = new ProcessRunner(listener, values);

            }

        }

        public void send(String cmd) {
            // Send user input to the running process...
        }

    }

    public class ProcessRunner extends Thread {

        private List<String> cmds;
        private CommandListener listener;

        public ProcessRunner(CommandListener listener, List<String> cmds) {
            this.cmds = cmds;
            this.listener = listener;
            start();
        }

        @Override
        public void run() {
            try {
                System.out.println("cmds = " + cmds);
                ProcessBuilder pb = new ProcessBuilder(cmds);
                pb.redirectErrorStream();
                Process p = pb.start();
                StreamReader reader = new StreamReader(listener, p.getInputStream());
                // Need a stream writer...

                int result = p.waitFor();

                // Terminate the stream writer
                reader.join();

                listener.commandCompleted(null, result);
            } catch (Exception exp) {
                exp.printStackTrace();
            }
        }

    }

    public class StreamReader extends Thread {

        private InputStream is;
        private CommandListener listener;

        public StreamReader(CommandListener listener, InputStream is) {
            this.is = is;
            this.listener = listener;
            start();
        }

        @Override
        public void run() {
            try {
                int value = -1;
                while ((value = is.read()) != -1) {
                    listener.commandOutput(Character.toString((char) value));
                }
            } catch (IOException exp) {
                exp.printStackTrace();
            }
        }

    }

}

PS- I was running this on my Mac, so you might need to put in a call to "cmd" for Windows... ;)

PPS- This is an incomplete example, if it wasn't 1am I might fill it in, but, this doesn't stop the user from pressing back space beyond the last known user input position. If I was going to fix this, I would use a DocumentFilter and simply "protect" all the text before the user position, disallowing the user from removing it

Updated with "Protected DocumentFilter" example

Added a "protected" DocumentFilter to protected areas of the Document that the user should no longer be allowed to edit.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

public class QuickTerminal {

    public static void main(String[] args) {
        new QuickTerminal();
    }

    public QuickTerminal() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new ConsolePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public interface CommandListener {

        public void commandOutput(String text);

        public void commandCompleted(String cmd, int result);

        public void commandFailed(Exception exp);
    }

    public class ConsolePane extends JPanel implements CommandListener, UserInput {

        private JTextArea textArea;
        private int userInputStart = 0;
        private Command cmd;

        public ConsolePane() {

            cmd = new Command(this);

            setLayout(new BorderLayout());
            textArea = new JTextArea(20, 30);
            ((AbstractDocument)textArea.getDocument()).setDocumentFilter(new ProtectedDocumentFilter(this));
            add(new JScrollPane(textArea));

            textArea.addKeyListener(new KeyAdapter() {
                @Override
                public void keyPressed(KeyEvent e) {
                    if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                        int range = textArea.getCaretPosition() - userInputStart;
                        try {
                            String text = textArea.getText(userInputStart, range).trim();
                            System.out.println("[" + text + "]");
                            userInputStart += range;
                            if (!cmd.isRunning()) {
                                cmd.execute(text);
                            } else {
                            }
                        } catch (BadLocationException ex) {
                            Logger.getLogger(QuickTerminal.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    } else {
//                        if (!cmd.isRunning()) {
//                            cmd.send(...);
//                        }
                    }
                }
            });
        }

        @Override
        public void commandOutput(String text) {
            SwingUtilities.invokeLater(new AppendTask(textArea, text));
        }

        @Override
        public void commandFailed(Exception exp) {
            SwingUtilities.invokeLater(new AppendTask(textArea, "Command failed - " + exp.getMessage()));
        }

        @Override
        public void commandCompleted(String cmd, int result) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    int pos = textArea.getCaretPosition();

                    System.out.println("pos = " + pos + "; length = " + textArea.getText().length());

                    textArea.setCaretPosition(textArea.getText().length());
                    userInputStart = pos;
                }
            });
        }

        @Override
        public int getUserInputStart() {
            return userInputStart;
        }
    }

    public interface UserInput {

        public int getUserInputStart();
    }

    public class AppendTask implements Runnable {

        private JTextArea textArea;
        private String text;

        public AppendTask(JTextArea textArea, String text) {
            this.textArea = textArea;
            this.text = text;
        }

        @Override
        public void run() {
            textArea.append(text);
        }
    }

    public class Command {

        private CommandListener listener;
        private ProcessRunner runner;

        public Command(CommandListener listener) {
            this.listener = listener;
        }

        public boolean isRunning() {

            return runner != null && runner.isAlive();

        }

        public void execute(String cmd) {

            if (!cmd.trim().isEmpty()) {


                List<String> values = new ArrayList<>(25);
                if (cmd.contains("\"")) {

                    while (cmd.contains("\"")) {

                        String start = cmd.substring(0, cmd.indexOf("\""));
                        cmd = cmd.substring(start.length());
                        String quote = cmd.substring(cmd.indexOf("\"") + 1);
                        cmd = cmd.substring(cmd.indexOf("\"") + 1);
                        quote = quote.substring(0, cmd.indexOf("\""));
                        cmd = cmd.substring(cmd.indexOf("\"") + 1);

                        if (!start.trim().isEmpty()) {
                            String parts[] = start.trim().split(" ");
                            values.addAll(Arrays.asList(parts));
                        }
                        values.add(quote.trim());

                    }

                    if (!cmd.trim().isEmpty()) {
                        String parts[] = cmd.trim().split(" ");
                        values.addAll(Arrays.asList(parts));
                    }

                    for (String value : values) {
                        System.out.println("[" + value + "]");
                    }

                } else {

                    if (!cmd.trim().isEmpty()) {
                        String parts[] = cmd.trim().split(" ");
                        values.addAll(Arrays.asList(parts));
                    }

                }

                runner = new ProcessRunner(listener, values);

            }

        }

        public void send(String cmd) {
            // Send user input to the running process...
        }
    }

    public class ProcessRunner extends Thread {

        private List<String> cmds;
        private CommandListener listener;

        public ProcessRunner(CommandListener listener, List<String> cmds) {
            this.cmds = cmds;
            this.listener = listener;
            start();
        }

        @Override
        public void run() {
            try {
                System.out.println("cmds = " + cmds);
                ProcessBuilder pb = new ProcessBuilder(cmds);
                pb.redirectErrorStream();
                Process p = pb.start();
                StreamReader reader = new StreamReader(listener, p.getInputStream());
                // Need a stream writer...

                int result = p.waitFor();

                // Terminate the stream writer
                reader.join();

                listener.commandCompleted(null, result);
            } catch (Exception exp) {
                exp.printStackTrace();
            }
        }
    }

    public class StreamReader extends Thread {

        private InputStream is;
        private CommandListener listener;

        public StreamReader(CommandListener listener, InputStream is) {
            this.is = is;
            this.listener = listener;
            start();
        }

        @Override
        public void run() {
            try {
                int value = -1;
                while ((value = is.read()) != -1) {
                    listener.commandOutput(Character.toString((char) value));
                }
            } catch (IOException exp) {
                exp.printStackTrace();
            }
        }
    }

    public class ProtectedDocumentFilter extends DocumentFilter {

        private UserInput userInput;

        public ProtectedDocumentFilter(UserInput userInput) {
            this.userInput = userInput;
        }

        public UserInput getUserInput() {
            return userInput;
        }

        @Override
        public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
            if (offset >= getUserInput().getUserInputStart()) {
                super.insertString(fb, offset, string, attr);
            }
        }

        @Override
        public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
            if (offset >= getUserInput().getUserInputStart()) {
                super.remove(fb, offset, length); //To change body of generated methods, choose Tools | Templates.
            }
        }

        @Override
        public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
            if (offset >= getUserInput().getUserInputStart()) {
                super.replace(fb, offset, length, text, attrs); //To change body of generated methods, choose Tools | Templates.
            }
        }
    }
}



回答2:


I would suggest that when any other key is released, if starflag = true you store the start, and set startflag to false as you said, and when "enter" is actually pressed, you can do startflag = true; and store the end as the getCaretPosition().

My understanding of your intentions beyond that is slightly vague, but here are my ideas: If you have an entire "conversation" of sorts going on in your console, and you want ALL of the user entries, then you could simply use an ArrayList userinputs, and instead of start = console.getCaretPosition(), you could do userinputs.add(new Point(console.getCaretPosition(),-1)); and then when the user ends his input(or before STDOUT sends input), do userinputs.get(userinputs.size()-1).y = console.getCaretPosition()(Or you could store a temporary point, and only add the point upon it's completion - when it get an end as well.)

If you are sending the user input to the output whenever the enter key is pressed, then I don't see what more is needed than the simple code above, that essentially works like this:

public void keyReleased(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
    startflag = true;
    //Just get the text from the start(stored below), and up until where the caret is now, as the users output.
}else{
    if(startflag){
         start = console.getCaretPosition()
         startflag = false;
    }
}
}


来源:https://stackoverflow.com/questions/15017148/jtextarea-as-io-console

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