Link to home
Start Free TrialLog in
Avatar of eric2405
eric2405

asked on

Running Command Prompt within Java GUI

How do I run the Command prompt within a java GUI?(i.e. I know how to "invoke" the Dos Prompt from java, what I need is to run Dos and its commands within the GUI).

Below is the code I've been working with, it only display the first lines of the command prompt on the text field and doesn't allow me to interact with dos. What do I need to do?
Please I do need a clear answer.
THANKS ever so much experts.

import java.lang.*;
import java.io.*;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;

public class Dos implements Runnable
{
     private PipedOutputStream pipeout;
     private PipedOutputStream pipeerr;
     String command = "cmd";

     public Dos ( String[] cmd )
     
     {
      pipeout = null;
      pipeerr = null;
     }

     public void run ()
     {
      exec ();
     }

     public void exec ()
     {

          // Class to redirect the process input stream to a piped output stream

          class OutputMonitor implements Runnable
          {
               InputStream is;
               PipedOutputStream pout;

               public OutputMonitor ( InputStream i, PipedOutputStream p )
               {
                is = i;
                pout = p;
               }
               public void run ()
               {
                    try
                    {
                         int inputChar;

                         for ( ;; )
                         {
                            inputChar = is.read();
                            if ( inputChar == -1 )
                            { break; }

                            if ( pout == null )
                            {
                                 System.out.write ( inputChar );
                            }
                            else
                            {
                                 pout.write ( inputChar );

                            }
                       }
                       if ( pout != null )
                       {
                            pout.flush ();
                            pout.close ();
                       }
                       else
                       {
                            System.out.flush();
                       }
                    }
                    catch ( Exception e ) { e.printStackTrace (); }
               }
            }

          try
          {
               Runtime r = Runtime.getRuntime ();
               Process p = r.exec (command);

               OutputMonitor out = new OutputMonitor ( p.getInputStream (), pipeout );
               OutputMonitor err = new OutputMonitor ( p.getErrorStream (), pipeerr );

               Thread t1 = new Thread ( out  );
               Thread t2 = new Thread ( err );

               t1.start ();
               t2.start ();

          }
          catch ( Exception e ) { e.printStackTrace (); }

     }

     public PipedInputStream getInputStream () throws IOException
     {
          pipeout = new PipedOutputStream ();
          return new PipedInputStream ( pipeout );
     }

     public PipedInputStream getErrorStream () throws IOException
     {
          pipeerr = new PipedOutputStream ();
          return new PipedInputStream ( pipeerr );
     }

     public void execInThread ()
     {
          Thread t = new Thread ( this );
          t.start ();
     }

     public static JPanel getContentPane ( JTextArea ta )
     {

          JPanel p = new JPanel ( new BorderLayout () );
          JPanel bottom = new JPanel ( new FlowLayout () );
          JButton button = new JButton ( " Exit " );
          button.addActionListener ( new ActionListener ( )
                              {
                                   public void actionPerformed ( ActionEvent e )
                                   {
                                        System.exit ( 0 );
                                   }
                              }
                         );


          bottom.add ( button );

          p.add ( new JScrollPane ( ta ), BorderLayout.CENTER );
          p.add ( bottom, BorderLayout.SOUTH );
          p.setPreferredSize ( new Dimension ( 640,480 ) );
          return p;
    }

     public static void main ( String[] arg )
     {
         
          // Class run in a thread,listens for the process output
          // and forwards it to the UI via invokeLater()

          class GuiUpdate implements Runnable
          {
               private PipedInputStream pin;
               private PipedInputStream perr;
               private JTextArea outputArea;

               GuiUpdate ( JTextArea textArea, PipedInputStream in )
               {
                 pin = in;
                 outputArea = textArea;
               }

              public void run ()
               {
                    // Class to run on the event dispatch thread to update the GUI

                    class UpdateSwing implements Runnable
                    {
                         String update;
                         JTextArea swingTextArea;

                         public UpdateSwing ( JTextArea a, String s )
                         {
                              update = s;
                              swingTextArea = a;
                         }
                         public void run ()
                         {
                              outputArea.append ( update + "\n" );
                         }
                    }

                    try
                    {
                         // Read file before displaying
                         BufferedReader r = new BufferedReader ( new InputStreamReader ( pin ) );
                         String line;

                         for ( ;; )
                         {
                              line = r.readLine ();
                              if ( line == null ) { break; }

                              SwingUtilities.invokeLater ( new UpdateSwing ( outputArea, line ) );

                              Thread.yield ();
                         }
                    }
                    catch ( Exception e ) { e.printStackTrace (); }
               }
          }

          // Create and invoke GUI

          JFrame f = new JFrame ( "GUI for Dos" );
          f.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
          JTextArea textOutput = new JTextArea ();
          f.getContentPane().add ( getContentPane ( textOutput ) );
          f.pack();
          f.show ();

          // Start command and capture output in the scrollable text area

          try
          {
               // Create command and setup the pipes

               Dos d = new Dos ( arg );

               PipedInputStream stdout_pipe = d.getInputStream ();
               PipedInputStream stderr_pipe = d.getErrorStream ();
               d.execInThread ( );
               
              // Results

               Thread t1 = new Thread ( new GuiUpdate ( textOutput, stdout_pipe ) );
               Thread t2 = new Thread ( new GuiUpdate ( textOutput, stderr_pipe ) );

               t1.start ();
               t2.start ();

          }
          catch ( Exception e ) { e.printStackTrace (); }
     }
}

Avatar of savalou
savalou

A few comments:

1.  I don't think you should be closing everything down if there is no input in the run() method of OutputMonitor.
2.  Any new commands to be run should be writen to the OutputStream of your Process.
3.  You could set a KeyListener on your TextArea to listen for key presses, and echo these to the OutputStream of your Process.

class MyKeyListener implements KeyListener {

      public void keyTyped(KeyEvent e) {
        System.out.println("key typed: " + e.getKeyChar());
      }
      public void keyPressed(KeyEvent e) {
        System.out.println("pressed");
      }
      public void keyReleased(KeyEvent e) {
        System.out.println("released");
      }
}

I think you should move some of the code around and break it up into different classes for clarity (you probably had them all in one file to post here?).

Good luck.
ASKER CERTIFIED SOLUTION
Avatar of doronb
doronb

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
As you can see TestApplication and TestFrame simply serve GUI purposes.

ExecProcessor is an interface that includes methods needed to process INPUT/ERROR signals from the process being executed by Java code.

ExecHelper is the interesting class since it carries out the job. It first spawns the process, binds its streams and controls the threads it uses to monitor the I/O activity of the spawned process.

The way this program is designed and implemented you can substitute any other GUI instead of TestApplication and TestFrame and as long as you have an ExecProcessor responding to the process events and an ExecHelper to start the process, all will work exactly as it does in my example.

Hope this helps,
Doron
I would like to add that I am sorry for not really fixing your code so that it would work.  I felt that it would be a better approach to present you with code that is modular, documented and most importantly, works in a way that would suit more than just running the DOS command line interface.

Good luck,
Doron
Avatar of eric2405

ASKER

Thanks for the comments savalou

Thanks ever so much for your help Doron.
Now I must be doing something really stupid because I can't get the program to work.
I have put the .java programs in two different packages. This is what I get when I try to compile the programs.

ExecProcessor.java
(Compiled)

ExecHelper.java
C:\dev\exec\tester\dev\exec\util\ExecHelper.java:21: cannot resolve symbol
symbol  : class ExecProcessor
location: class dev.exec.util.ExecHelper
     private ExecProcessor handler;
             ^
C:\dev\exec\tester\dev\exec\util\ExecHelper.java:23: cannot resolve symbol
symbol  : class ExecProcessor
location: class dev.exec.util.ExecHelper
     private ExecHelper(ExecProcessor ep, Process p) {
                        ^
C:\dev\exec\tester\dev\exec\util\ExecHelper.java:59: cannot resolve symbol
symbol  : class ExecProcessor
location: class dev.exec.util.ExecHelper
     public static ExecHelper exec(ExecProcessor handler, String command) throws IOException {
                                   ^
3 errors
Tool completed with exit code 1

TestFrame.java
(Compiled)

TestApplication.java
C:\dev\exec\tester\TestApplication.java:13: cannot resolve symbol
symbol  : class TestFrame
location: class dev.exec.tester.TestApplication
          TestFrame frame = new TestFrame();
          ^
C:\dev\exec\tester\TestApplication.java:13: cannot resolve symbol
symbol  : class TestFrame
location: class dev.exec.tester.TestApplication
          TestFrame frame = new TestFrame();
                                ^
2 errors
Tool completed with exit code 1

I am sorry to ask again, but please where have I gone wrong?
Thanks again Doron I really appreciate your help
Eric

The correct file structure of the source directory is like this:

C:.
└───dev
      └───exec
            ├───tester
            │      ├───TestApplication.java
            │      └───TestFrame.java
            └───util
                  ├───ExecHelper.java
                  └───ExecProcessor.java

Once you have all the sources in the correct directories according to the above layout, everything should compile without problems.  You could also just remove the package decleration from the code and compile it all from one source directory, this should work as well.

Hope this helps,
Doron
Ummmm, yes... Directory trees do not appear so nicely here... lets see if this works better:

C:.
+-------dev
      +-------exec
            +-------tester
            |      +---TestApplication.java
            |      +---TestFrame.java
            |
            +-------util
                  +---ExecHelper.java
                  +---ExecProcessor.java
Slightly better, well, the idea is that first you have the "dev" folder, within it you have the "exec" folder, with in that you have the "util" and "tester" folders.  The "util" folder contains the "ExecHelper.java" and "ExecProcessor.java" files; while the "tester" folder has the "TestApplication.java" and "TestFrame.java" files.

Sorry about this mess, I wish I'd've posted all of this in one post :)
Doron
Fine it works now! That is exactly what I needed
Thank you very much indeed Doron for an excellent help
Eric
You're welcome :)