Spinning command line cursor in Java

As a follow-up to my previous article on displaying a spinning cursor to display program activity, I have created a more useful example that could be adapted for use.

The original problem was this – I was writing a program that performed a particular task and I needed some way of showing the program was alive and functioning correctly whilst doing the task.

In Windows this is done by changing the mouse cursor into an hourglass, unfortunately on the command line we don’t have such GUI luxuries. One classic option is to create a spinning line by displaying | / – \ and so on.

The example below creates two child threads; one to do a particular job (in this case slowly count to 10) and another thread to display a spinning cursor.

/**
 * Spinning cursor test class
 *
 * @author Nick Giles
 */
public class SpinTest
{
    /**
     * Thread which does the stuff we're interested in
     *
     */
    private Thread stuff;
    
    /**
     * Thread class which does stuff in the background
     *
     */
    private class Stuff implements Runnable
    {
        public void run()
        {
            int result = 0;
            
            try
            {
                // Slowly count to 10, although you can of course put whatever 
                // you want here, presumably something a bit more useful
                while (result < 10)
                {
                    result++;
                    Thread.sleep(1000);
                }
            }
            catch (InterruptedException e)
            {
                // If interrupted then quietly end the thread, you may well
                // want to handle this in some way
            }
        }
    }
    
    /**
     * Spinner thread
     *
     */
    private class Spinner implements Runnable
    {
        public void run()
        {
            String[] phases = {"|", "/", "-", "\\"};
            
            try
            {
                while (true)
                {
                    for (String phase : phases)
                    {
                        System.out.printf("\b"+phase);
                        
                        Thread.sleep(100);
                    }
                }
            }
            catch (InterruptedException e)
            {
                // No need to do anything if interrupted
            }
        }
    }

    /**
     * Handles all shutdown functions
     *
     */
    public class ShutdownHandler extends Thread
    {
        public void run()
        {
            // On interrupt, stop doing stuff
            stuff.interrupt();
        }
    }

    
    public void doStuff()
    {
        try
        {
            // Attach an object to handle shutdown signals (i.e. ctrl+c)
            Runtime.getRuntime().addShutdownHook(new ShutdownHandler()); 
            
            // Create a new thread for spinning the cursor
            Thread spinner = new Thread(new Spinner());
            
            // Create a new thread for doing stuff
            this.stuff = new Thread(new Stuff());
            
            // Nice message to user
            System.out.printf("Doing stuff...  ");
            
            // Start doing stuff
            this.stuff.start();
            
            // Start spinning the cursor
            spinner.start();
            
            // Check the thread doing stuff is still doing stuff
            while (stuff.isAlive())
            {
                stuff.join(1000);
            }
            
            System.out.printf("\bDone.\n");
            
            // The thread doing stuff has finished, so stop spinning
            spinner.interrupt();
            
            // Wait for the spinning thread to terminate
            spinner.join();
            
            System.out.println("The End.");
        }
        catch (InterruptedException e)
        {
            System.out.println("Interrupted");
        }
    }
    
    /**
     * Main method
     *
     */
    public static void main(String[] args)
    {
        SpinTest test = new SpinTest();
        
        test.doStuff();
    }
}

It’s a fairly basic implementation but it should be fairly simple to extend it for a real-world application.

This entry was posted in Java and tagged , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *