Вы находитесь на странице: 1из 8

Java Console apps made easy - CodeProject

1 of 8

http://www.codeproject.com/Articles/328417/Java-Console-apps-made...

Articles Languages Java Beginners

Java Console apps made easy


David MacDermot, 10 Feb 2012

CPOL

4.88 (16 votes)


This article describes the creation of a Java console type application.

Download demo - 192 KB


Download source - 22.4 KB

Contents
Introduction
How to use this Java Console
How to wire up a console
Making a custom block caret
Extra! Extra! The menu system.

25/02/2016 14:24

Java Console apps made easy - CodeProject

2 of 8

http://www.codeproject.com/Articles/328417/Java-Console-apps-made...

Final comments
History

Introduction
The humble console app: I write them all the time creating one off tests to explore new coding ideas. I'll even string up quick,
menu based, test applications for testing remote device communications and command sets, where the number of commands
can grow during the product development cycle. The advantage of course, is that to grow the application I only have to add a
menu item and an event handler in the code. That is far preferable to squeezing more fields onto an already crowded Windows
Forms application. Sometimes you don't know what you have till it's gone.
I decided to tackle Java this year and get a feel for the language and tools. I usually take on a new (for me) language by
translating an application I have written into the new language and stumbling through the thorny issues as I encounter them. I
was surprised at how many of the things I took for granted in C# turned out to be rather hard to do in Java; case in point, the
console app.
The application I chose to port to Java happened to be a console based menu driven application. Porting the menu code was
fairly straightforward once I figured out how to substitute an interface and nested Java class for a C# delegate in order to obtain
callback behavior. The real headache lay in the performance of the application's menu code in an actual Windows console
instance.
Java applications utilize STDIN, STDOUT, and STDERR streams but do not own the console instance displaying the streams.
Since Java aims at a broad range of Operating Systems, it doesn't include support for clearing the screen. I tried a number of
work-a-rounds to get my application to function as intended without acceptable results.
I was about to give up when I took a different track and considered duplicating console functionality in a Java GUI widget. This
turned out to be more promising. There were quite a few examples of redirecting STDOUT and STDERR to a JtextArea but
I was unable to find one that also successfully copied keyboard input to STDIN. What I did find was quite a bit of chatter from
other developers indicating a desire for such a component.
I began to test the various code solutions and snippets that I had found and settled on one particularly robust example[^]. I
then added some code to pipe keyboard characters to STDIN, added a public clear() method, and some properties to
customize the look and feel of the console. Finally I figured out how to create a custom blinking block cursor for
JavaConsole to round things off.

How to use this Java Console


Minimally all that is necessary to use this Java Console in your project is to declare an instance of the JavaConsole class.
public static void main(String[] args) {
new JavaConsole();
scanner = new Scanner(System.in);
System.out.println("Hello World!");
scanner.nextLine();
System.exit(0);
}
Here is an example of how to customize the look of the Java Console.
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
JavaConsole console = new JavaConsole();
//Customize the console text field
console.setBackground(Color.WHITE);
console.setForeground(Color.BLACK);

25/02/2016 14:24

Java Console apps made easy - CodeProject

3 of 8

http://www.codeproject.com/Articles/328417/Java-Console-apps-made...

console.setFont(new Font ("Ariel", Font.BOLD, 12));


//Customize the console frame
console.setTitle("Hello World Program");
Image im = Toolkit.getDefaultToolkit().getImage("../images/MyIcon.png");
console.setIconImage(im);
System.out.println("Hello World!");
scanner.nextLine();
System.exit(0);
}
Here is an example using the JavaConsole.clear() method to clear the screen between chunks of text.
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
JavaConsole console = new JavaConsole();
System.out.println(
"It was a dark and stormy night; the rain fell in torrents, except at " +
"occasional intervals, when it was checked by a violent gust of wind " +
"which swept up the streets (for it is in London that our scene lies), " +
"rattling along the house-tops, and fiercely agitating the scanty flame " +
"of the lamps that struggled against the darkness. Through one of the " +
"obscurest quarters of London, and among haunts little loved by the " +
"gentlemen of the police, a man, evidently of the lowest orders, was " +
"wending his solitary way.");
scanner.nextLine();
console.clear();
System.out.println(
"He stopped twice or thrice at different shops and houses of a description " +
"correspondent with the appearance of the quartier in which they were situated, " +
"and tended inquiry for some article or another which did not seem easily " +
"to be met with. All the answers he received were couched in the negative; " +
"and as he turned from each door he muttered to himself, in no very elegant " +
"phraseology, his disappointment and discontent. At length, at one house, " +
"the landlord, a sturdy butcher, after rendering the same reply the inquirer " +
"had hitherto received, added, \"But if this vill do as vell, Dummie, it is " +
"quite at your sarvice!\"");
scanner.nextLine();
System.exit(0);
}
Finally, here's a comprehensive list of Java Console custom features.
console.getBackground();
console.getForeground();
console.getFont();
console.setBackground(Color);
console.setForeground(Color);
console.setFont(Font);
console.setTitle(title);
console.setIconImage(Image);
console.clear();

How to wire up a console


25/02/2016 14:24

Java Console apps made easy - CodeProject

4 of 8

http://www.codeproject.com/Articles/328417/Java-Console-apps-made...

The first thing we need to do is to redirect STDOUT and STDERR to our JtextArea. The code class I started with achieved
this in the following manner.
1. Establish some Piped Input Streams.
private final PipedInputStream pin=new PipedInputStream();
private final PipedInputStream pin2=new PipedInputStream();
2. Hook the input streams up to the associated output streams.
PipedOutputStream pout=new PipedOutputStream(this.pin);
PipedOutputStream pout2=new PipedOutputStream(this.pin2);
3. Redirect System STDOUT and STDERR to these output streams.
System.setOut(new PrintStream(pout,true));
System.setErr(new PrintStream(pout2,true));
4. Spin up some threads to read from the Piped Input Streams.
//Declarations
private Thread reader;
private Thread reader2;
//In the class constructor
reader=new Thread(this);
reader.setDaemon(true);
reader.start();
reader2=new Thread(this);
reader2.setDaemon(true);
reader2.start();
5. Monitor STDOUT and STDERR appending the text to the JtextArea.
public synchronized void run()
{
try
{
while (Thread.currentThread()==reader)
{
try { this.wait(100);}catch(InterruptedException ie) {}
if (pin.available()!=0)
{
String input=this.readLine(pin);
textArea.append(input);
textArea.setCaretPosition(textArea.getDocument().getLength()); //DWM
02-07-2012
}
if (quit) return;
}
while (Thread.currentThread()==reader2)
{
try { this.wait(100);}catch(InterruptedException ie) {}
if (pin2.available()!=0)
{
String input=this.readLine(pin2);
textArea.append(input);
textArea.setCaretPosition(textArea.getDocument().getLength()); //DWM
02-07-2012
}
if (quit) return;
}
} catch (Exception e)
{

25/02/2016 14:24

Java Console apps made easy - CodeProject

5 of 8

http://www.codeproject.com/Articles/328417/Java-Console-apps-made...

textArea.append("\nConsole reports an Internal error.");


textArea.append("The error is: "+e);
textArea.setCaretPosition(textArea.getDocument().getLength()); //DWM 02-07-2012
}
}
Now that we have STDOUT and STDERR piped to the JtextArea, we need to monitor keyboard input to the JtextArea
and copy the characters to STDIN. I modified the original code to do so as follows:
1. Establish a Piped Output Stream for reading keyboard input.
private final PipedOutputStream pout3=new PipedOutputStream();
2. Hook the output stream to an associated input stream and redirect STDIN to this input stream.
System.setIn(new PipedInputStream(this.pout3));
3. Add a KeyListener and copy out keyboard input as it arrives.
textArea.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {
try { pout3.write(e.getKeyChar()); } catch (IOException ex) {}
}});

Making a custom block caret


The default caret of the JtextArea is a vertical bar but I wanted a prompt that was a bit more prominent. It turns out that this
feature is customizable and I found some examples on how to do this. Refer to A custom caret class [^] and Fancier custom
caret class [^] to get an idea of how it's done. Here is the code for my flashing block caret:
public class BlockCaret extends DefaultCaret {
private static final long serialVersionUID = 1L;
/**
* @brief Class Constructor
*/
public BlockCaret() {
setBlinkRate(500); // half a second
}
/* (non-Javadoc)
* @see javax.swing.text.DefaultCaret#damage(java.awt.Rectangle)
*/
protected synchronized void damage(Rectangle r) {
if (r == null)
return;
// give values to x,y,width,height (inherited from java.awt.Rectangle)
x = r.x;
y = r.y;
height = r.height;
// A value for width was probably set by paint(), which we leave alone.
// But the first call to damage() precedes the first call to paint(), so
// in this case we must be prepared to set a valid width, or else
// paint()
// will receive a bogus clip area and caret will not get drawn properly.

25/02/2016 14:24

Java Console apps made easy - CodeProject

6 of 8

http://www.codeproject.com/Articles/328417/Java-Console-apps-made...

if (width <= 0)
width = getComponent().getWidth();
repaint();
repaint();

//Calls getComponent().repaint(x, y, width, height) to erase


// previous location of caret. Sometimes one call isn't enough.

}
/* (non-Javadoc)
* @see javax.swing.text.DefaultCaret#paint(java.awt.Graphics)
*/
public void paint(Graphics g) {
JTextComponent comp = getComponent();
if (comp == null)
return;
int dot = getDot();
Rectangle r = null;
char dotChar;
try {
r = comp.modelToView(dot);
if (r == null)
return;
dotChar = comp.getText(dot, 1).charAt(0);
} catch (BadLocationException e) {
return;
}
if(Character.isWhitespace(dotChar)) dotChar = '_';
if ((x != r.x) || (y != r.y)) {
// paint() has been called directly, without a previous call to
// damage(), so do some cleanup. (This happens, for example, when
// the text component is resized.)
damage(r);
return;
}
g.setColor(comp.getCaretColor());
g.setXORMode(comp.getBackground()); // do this to draw in XOR mode
width = g.getFontMetrics().charWidth(dotChar);
if (isVisible())
g.fillRect(r.x, r.y, width, r.height);
}
}

Extra! Extra! The menu system


I have included the menu system, that I like to use so much, in this demo. It is a Java port of the easy to use console menu
featured in this CodeProject article [^]. As I mentioned in the Introduction, working with callbacks in Java is a bit different than
C# and the Menu class illustrates this well. Here's how it's done in C#.
1. I declare a delegate (a function pointer):
delegate void MenuCallback();
2. Next I create some event handlers for menu picks:
private static void HandleItem1
{
Console.WriteLine("You chose item 1.\n");
Console.Read();
}

25/02/2016 14:24

Java Console apps made easy - CodeProject

7 of 8

http://www.codeproject.com/Articles/328417/Java-Console-apps-made...

private static void HandleItem2


{
Console.WriteLine("You chose item 2.\n");
Console.Read();
}
3. Then I add them to the Menu like so:
menu = new Menu();
menu.Add("Item 1", new MenuCallback(HandleItem1));
menu.Add("Item 2", new MenuCallback(HandleItem2));
menu.Show();
Java does not allow for the passing of function pointers and thus delegates. Instead this behavior is restricted to typed object
pointers and thus the class interface becomes the Java equivalent of the delegate. Here's how it's done in Java.
1. I declare an interface (a typed object pointer):
public interface MenuCallback extends EventListener {
public void Invoke();
}
2. Next I create some event handlers for menu picks:
private static void HandleItem1 {
System.out.println("You chose item 1.\n.");
scanner.nextLine();
}
private static void HandleItem2 {
System.out.println("You chose item 2.\n.");
scanner.nextLine();
}
3. Then I add them to the Menu like so:
Menu menu = new Menu(console);
menu.add("Item 1", new MenuCallback() { public void Invoke() {
HandleItem1(); } });
menu.add("Item 2", new MenuCallback() { public void Invoke() {
HandleItem2(); } });
menu.show();
It's a bit more verbose since we are in effect, having to wrap our function pointer in a class.

Final comments
The menu system does not work well in the standard console when used in a Java application. The version of Menu class
included here should only be used in this Java Console. This Java Console may be used anytime you want to have a console
window that is owned by your application. While it features a clear() method for clearing the screen it does not, however
handle DOS commands or provide a command prompt.

History
Feb 09, 2012: Version 1.0.0.0.

License

25/02/2016 14:24

Java Console apps made easy - CodeProject

8 of 8

http://www.codeproject.com/Articles/328417/Java-Console-apps-made...

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share
About the Author
David MacDermot
United States
No Biography provided

You may also be interested in...


Lucene.Net ultra fast search for
MVC or WebForms site =>
made easy!

SharePoint Governance: A
definitive Guide

NHibernate Made Simple

SAPrefs - Netscape-like
Preferences Dialog

Processes and threads made


easy

Window Tabs (WndTabs) Add-In


for DevStudio

Comments and Discussions


12 messages have been posted for this article Visit http://www.codeproject.com/Articles/328417/Java-Consoleapps-made-easy to post and view comments on this article, or click here to get a print view with messages.
Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.160217.1 | Last Updated 10 Feb 2012

Selecione o idioma

Article Copyright 2012 by David MacDermot


Everything else Copyright CodeProject, 1999-2016

25/02/2016 14:24