views:

704

answers:

6

Hi,

I have a bit of an unusual question: How can I create a "Command Console" using Swing?

What I want to have is a console where the users type in commands, press enter, and the output from the command is displayed under. I don't want to allow the user to change the "prompt" and older output. I am thinking of something like Windows CMD.EXE.

I had a look at this question, however it doesn't answer my question.

A: 

You can execute arbitrary commands with Plexus using Commandline. It handles escaping of the arguments, environment specific execution, and allows you to attach consumers to stdout and stderr, leaving you to focus on the handling.

Here's a link to another answer I gave, showing how you can set up a Commandline and handle the output.

Rich Seller
A: 
Vinay Sajip
+1  A: 

If I understand your question correctly, you're looking to execute commands specific to your application. My advice would be, if this is in fact the case, to use two textareas, one that's a single line and one that takes up the rest of the space. Add some keypress event handlers to the small one, which would be editable, and make the other one read-only. If you must have a single text area, you could make it read-only and then add a few keypress handlers to handle character input and up/down keypresses.

Hope I've understood your question correctly, best of luck.

Jeff Cooper
A: 

I wouldn't try shortcuts (like groovy/beanshell) unless they fit your needs exactly. Trying to make a high-level tool do what you want when it's not what it already does can be the most frustrating thing about programming.

It should be fairly easy to take a text area and "Make it your own", but it would be much easier to do as someone else suggested and use a one-line text control combined with a multi-line display area.

In either case you want to keep pretty close control on the whole system, intercept and filter some keystrokes, disable input to the "Display" area if you decide to go with that, force a click on your display area to send focus to your input field, ...

If you do the single box thing, you'll want to make sure your input is always at the bottom of the box and that you control their cursor positioning (you probably don't want them able to do any input to any line except the last line).

I suggest you don't assume a single control is just going to work without modification, expect to do the legwork and everything will be fine.

Bill K
A: 

Try this code:

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

/** * * @author Alistair */ public class Console extends JPanel implements KeyListener {

private static final long serialVersionUID = -4538532229007904362L;
private JLabel keyLabel;
private String prompt = "";
public boolean ReadOnly = false;
private ConsoleVector vec = new ConsoleVector();
private ConsoleListener con = null;
private String oldTxt = "";
private Vector history = new Vector();
private int history_index = -1;
private boolean history_mode = false;

public Console() {
    super();
    setSize(300, 200);
    setLayout(new FlowLayout(FlowLayout.CENTER));
    keyLabel = new JLabel("");
    setFocusable(true);
    keyLabel.setFocusable(true);
    keyLabel.addKeyListener(this);
    addKeyListener(this);
    add(keyLabel);
    setVisible(true);
}

public void registerConsoleListener(ConsoleListener c) {
    this.con = c;
}

public String getPrompt() {
    return this.prompt;
}

public void setPrompt(String s) {
    this.prompt = s;
}

private void backspace() {
    if (!this.vec.isEmpty()) {
        this.vec.remove(this.vec.size() - 1);
        this.print();
    }
}

@SuppressWarnings("unchecked")
private void enter() {
    String com = this.vec.toString();
    String return$ = "";
    if (this.con != null) {
        return$ = this.con.receiveCommand(com);
    }

    this.history.add(com);
    this.vec.clear();
    if (!return$.equals("")) {
        return$ = return$ + "<br>";
    }
    // <HTML> </HTML>
    String h = this.keyLabel.getText().substring(6, this.keyLabel.getText().length() - 7);
    this.oldTxt = h.substring(0, h.length() - 1) + "<BR>" + return$;
    this.keyLabel.setText("<HTML>" + this.oldTxt + this.prompt + "_</HTML>");
}

private void print() {
    this.keyLabel.setText("<HTML>" + this.oldTxt + this.prompt + this.vec.toString() + "_</HTML>");
    this.repaint();
}

@SuppressWarnings("unchecked")
private void print(String s) {
    this.vec.add(s);
    this.print();
}

@Override
public void keyTyped(KeyEvent e) {
}

@Override
public void keyPressed(KeyEvent e) {
}

@Override
public void keyReleased(KeyEvent e) {
    this.handleKey(e);
}

private void history(int dir) {
    if (this.history.isEmpty()) {
        return;
    }
    if (dir == 1) {
        this.history_mode = true;
        this.history_index++;
        if (this.history_index > this.history.size() - 1) {
            this.history_index = 0;
        }
        // System.out.println(this.history_index);
        this.vec.clear();
        String p = (String) this.history.get(this.history_index);
        this.vec.fromString(p.split(""));

    } else if (dir == 2) {
        this.history_index--;
        if (this.history_index < 0) {
            this.history_index = this.history.size() - 1;
        }
        // System.out.println(this.history_index);
        this.vec.clear();
        String p = (String) this.history.get(this.history_index);
        this.vec.fromString(p.split(""));
    }

    print();

}

private void handleKey(KeyEvent e) {

    if (!this.ReadOnly) {
        if (e.getKeyCode() == 38 | e.getKeyCode() == 40) {
            if (e.getKeyCode() == 38) {
                history(1);
            } else if (e.getKeyCode() == 40 & this.history_mode != false) {
                history(2);
            }
        } else {
            this.history_index = -1;
            this.history_mode = false;
            if (e.getKeyCode() == 13 | e.getKeyCode() == 10) {
                enter();
            } else if (e.getKeyCode() == 8) {
                this.backspace();
            } else {
                if (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
                    this.print(String.valueOf(e.getKeyChar()));
                }
            }
        }
    }
}

}

class ConsoleVector extends Vector {

private static final long serialVersionUID = -5527403654365278223L;

@SuppressWarnings("unchecked")
public void fromString(String[] p) {
    for (int i = 0; i < p.length; i++) {
        this.add(p[i]);
    }
}

public ConsoleVector() {
    super();
}

@Override
public String toString() {
    StringBuffer s = new StringBuffer();
    for (int i = 0; i < this.size(); i++) {
        s.append(this.get(i));
    }
    return s.toString();
}

}

public interface ConsoleListener { public String receiveCommand(String command); }

It uses a JPanel as the panel and a JLabel as the console. The commands are passed to a CommandListener object and the returned value is printed to the console.

Kryten
A: 

BeanShell provides a JConsole, a command line input console with the following features:

  • a blinking cursor
  • command history
  • cut/copy/paste including selection with CTRL+arrow keys
  • command completion
  • Unicode character input
  • coloured text output
  • ...and it all comes wrapped in a scroll pane.

The BeanShell JARs are available from http://www.beanshell.org/download.html and the source is available via SVN from svn co http://ikayzo.org/svn/beanshell

For more info on JConsole see http://www.beanshell.org/manual/jconsole.html

Here is an example of using BeanShell's JConsole in your application:

import java.awt.Color;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;

import javax.swing.JFrame;

import bsh.util.GUIConsoleInterface;
import bsh.util.JConsole;

/** 
 * Example of using the BeanShell project's JConsole in
 * your own application.
 * 
 * JConsole is a command line input console that has support 
 * for command history, cut/copy/paste, a blinking cursor, 
 * command completion, Unicode character input, coloured text 
 * output and comes wrapped in a scroll pane.
 * 
 * For more info, see http://www.beanshell.org/manual/jconsole.html
 * 
 * @author tukushan
 */
public class JConsoleExample {

    public static void main(String[] args) {

     //define a frame and add a console to it
     JFrame frame = new JFrame("JConsole example");

     JConsole console = new JConsole();

     frame.getContentPane().add(console);
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setSize(600,400);

     frame.setVisible(true);

     inputLoop(console, "JCE (type 'quit' to exit): ");

     System.exit(0);
    }

    /**
     * Print prompt and echos commands entered via the JConsole
     * 
     * @param console a GUIConsoleInterface which in addition to 
     *         basic input and output also provides coloured text
     *         output and name completion
     * @param prompt text to display before each input line
     */
    private static void inputLoop(GUIConsoleInterface console, String prompt) {
     Reader input = console.getIn();
     BufferedReader bufInput = new BufferedReader(input);

     String newline = System.getProperty("line.separator");

     console.print(prompt, Color.BLUE);

     String line;
        try {
      while ((line = bufInput.readLine()) != null) {
          console.print("You typed: " + line + newline, Color.ORANGE);

          // try to sync up the console
          //System.out.flush();
          //System.err.flush();
          //Thread.yield();  // this helps a little

          if (line.equals("quit")) break; 
       console.print(prompt, Color.BLUE);
      }
      bufInput.close();
     } catch (IOException e) {
      e.printStackTrace();
     }

    }
}

NB: JConsole returns ";" if you hit Enter by itself.

tukushan