15

Is there any way I can make an executable .jar that will open up the command line when double clicked?

I'm making a text-based adventure game. As of right now it is just a maze with rooms. Eventually it is going to be much bigger and more in depth but for now I just want to get the basic structure down. Anyways, to make this work I've been getting output and input from the System.out.printf command and the java.util.Scanner. It's all working beautifully so far but I've realized I'm going to run into a problem when I try to send this to other people that don't know how or just don't want to run the program from the command line.

CaldwellYSR
  • 3,056
  • 5
  • 33
  • 50

13 Answers13

21

I found this while looking for an answer myself, I ended up writing this bit:

/**
 * This opens a command line and runs some other class in the jar
 * @author Brandon Barajas
 */
import java.io.*;
import java.awt.GraphicsEnvironment;
import java.net.URISyntaxException;
public class Main{
    public static void main (String [] args) throws IOException, InterruptedException, URISyntaxException{
        Console console = System.console();
        if(console == null && !GraphicsEnvironment.isHeadless()){
            String filename = Main.class.getProtectionDomain().getCodeSource().getLocation().toString().substring(6);
            Runtime.getRuntime().exec(new String[]{"cmd","/c","start","cmd","/k","java -jar \"" + filename + "\""});
        }else{
            THEMAINCLASSNAMEGOESHERE.main(new String[0]);
            System.out.println("Program has ended, please type 'exit' to close the console");
        }
    }
}

not sure if my answer is still relevant, but feel free to use it with the comment kept in o/

Only flaw I can think of is that it leaves the cmd window open after the program completes.

Usage: place this class in the same package as your main class and set it as the main class, it will open a command prompt window if one is not open, or if one is open launch the main class. Name / location of jar file is automatic. Designed for windows, but if you want it for another system just message me and I'll fix it. (I could do OS detection but I'm lazy and just making this so I can turn in a double-click jar file to my professor who uses windows).

Brandon Barajas
  • 226
  • 2
  • 3
  • Writing at 2am, should clarify, I found this post while looking for an answer and saw none, so I wrote this. – Brandon Barajas Mar 19 '15 at 07:02
  • It said "Error: Unable to access jarfile C:/660/efx/worskspace/... What's the reason for that? Can you fix it? – mk7 Oct 08 '15 at 14:30
  • @mk7 you probably forgot to replace "THEMAINCLASSNAMEGOESHERE" with the intended main class of your project, if not, give me the full error message. – Brandon Barajas Oct 09 '15 at 16:02
  • Already replaced that one and another one two lines above. Error: "Unable to access jarfile C:/eclipse/workspace/TestConsole/bin/" I tried to switch to another workspace and it's still the same error message on the cmd prompt window. I used Eclipse Mars and java sdk 1.8u60 – mk7 Oct 10 '15 at 17:42
  • 1
    Oh, I think I may know what's going on now. Are you trying to run it using eclipses native environment? You need to compile it into a jar first (with this as the main class for compilation purposes), then the jar will be double-clickable (there is no need for a script like this inside eclipse, since it creates a terminal environment for you). – Brandon Barajas Oct 12 '15 at 14:44
  • opening a cmd prompt window is not all that useful yet. Everyone can print log statement (using java.util.logging.Logger) onto an eclipse console easily. But how do you output the same statement onto this cmd prompt window at runtime? – mk7 Oct 13 '15 at 18:45
  • Normally it would be System.out.println() for this, but eclipse overrides the terminal environment (so it will just show up in the eclipse console. The purpose of this class is so when you compile a command line program, you can make it double-clickable (normally it wouldn't keep its own terminal environment open). – Brandon Barajas Oct 15 '15 at 15:12
  • `Runtime.getRuntime().exec(...)` returns a `Process` which can be used to close the console. – AleSod May 22 '17 at 14:24
  • what did you use that .substring(6) for? –  Sep 10 '17 at 19:12
  • @IchHabsDrauf it's because the .class.....toString() statement will return something like "file:/C:/...." The .subString(6) is used to remove: 'file:/'. – Brandon Barajas Sep 11 '17 at 19:59
  • @BrandonBarajas I get it now, thank you. But still why do you need to get a substring of that? –  Sep 16 '17 at 20:00
  • @IchHabsDrauf When I ran it without a substring I got "Error: Unable to access jarfile file:/....jar", but with it it worked fine. This is most-likely very much a windows specific, and maybe even CMD specific problem that I needed to make a workaround for, so I just cut out the "file:/" and it worked. – Brandon Barajas Sep 18 '17 at 04:55
5

If you want full control, you can implement a Console window in Swing which does what you have now.

If you cannot open said window (if headless) or the user asks for it on the command line, then just default to your current behaviour.

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
  • 1
    I didn't know much of anything about swing when I asked this question. After looking into it I managed to make something that didn't have anything to do with a Scanner and instead uses a JTextArea and a JTextField to get input and output. It works very well so thank you for this answer. – CaldwellYSR Nov 30 '11 at 02:22
  • What you mean by "Console window"? Are you talking about a window with a JTextArea that works like a console, or you are talking about an actual command line window like the cmd from Windows? – carloswm85 Oct 22 '19 at 20:01
  • @carloswm85 A Swing window. I do not know if it is possible to open a command line window using Windows specific API calls. – Thorbjørn Ravn Andersen Jan 19 '21 at 12:07
4

Double-clicking a jar opens it with whatever application you've associated to it in your OS. By default, javaw[.exe] is normally associated to jar files. That's the binary that runs without a terminal window. To see a terminal on double-click, you'd need to associate the java[.exe] binary with jar files.

Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199
2

Or you can provide a .sh .bat that will open a terminal and call your java in it.

YMomb
  • 2,366
  • 1
  • 27
  • 36
1

So this is my solution, I used the code from @Brandon Barajas and modified it. It creates a batchfile that starts the program by itself.

public static void main(String[] args){
    Console console = System.console();
    if(console == null && !GraphicsEnvironment.isHeadless()) {
        String filename = YOURMAINCALSS.class.getProtectionDomain().getCodeSource().getLocation().toString().substring(6);
        try {
            File batch = new File("Launcher.bat");
            if(!batch.exists()){
                batch.createNewFile();
                PrintWriter writer = new PrintWriter(batch);
                writer.println("@echo off");
                writer.println("java -jar "+filename);
                writer.println("exit");
                writer.flush();
            }
            Runtime.getRuntime().exec("cmd /c start \"\" "+batch.getPath());
        } catch(IOException e) {
            e.printStackTrace();
        }
    } else {
        //your program code...
    }
}

If you want you can add a writer.println("pause"); before the "exit" print, to keep the window open after the progam finishes. Then you need to hit ENTER to close the window.

1

You can use this program. This program creates a console for JAR programs (when JAR programs are run by double clicking on them).

import java.io.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.text.*;
import javax.swing.border.*;

class InitComponents {

    public static JFrame setupJFrameAndGet(String title, int width, int height) {
        JFrame tmpJF = new JFrame(title);
        tmpJF.setSize(width, height);
        tmpJF.setLocationRelativeTo(null);
        tmpJF.setLayout(null);
        tmpJF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        return tmpJF;
    } // end of setupJFrameAndGet

    public static JTextArea setupJTextAreaAndGet(String text, int rows, int columns, boolean setEditableFlag, boolean setLineWrapFlag, boolean setWrapStyleWordFlag, boolean setBoundsFlag, int xpos, int ypos, int width, int height) {
        JTextArea tmpJTA = new JTextArea(text, rows, columns);
        tmpJTA.setEditable(setEditableFlag);
        tmpJTA.setLineWrap(setLineWrapFlag);
        tmpJTA.setWrapStyleWord(setWrapStyleWordFlag);
        if (setBoundsFlag == true) {
            tmpJTA.setBounds(xpos, ypos, width, height);
        }
        return tmpJTA;
    } // end of setupJTextAreaAndGet

    public static JScrollPane setupScrollableJTextAreaAndGet(JTextArea jta, int xpos, int ypos, int width, int height) {
        JScrollPane tmpJSP = new JScrollPane(jta);
        tmpJSP.setBounds(xpos, ypos, width, height);
        return tmpJSP;
    } // end of setupScrollableJTextAreaAndGet

    public static JMenuBar setupJMenuBarAndGet() {
        JMenuBar tmpJMB = new JMenuBar();
        return tmpJMB;
    } // end of setupJMenuBarAndGet

    public static JMenu setupJMenuAndGet(String text) {
        JMenu tmpJM = new JMenu(text);
        return tmpJM;
    } // end of setupJMenuAndGet

    public static JMenuItem setupJMenuItemAndGet(String text) {
        JMenuItem tmpJMI = new JMenuItem(text);
        return tmpJMI;
    } // end of setupJMenuItemAndGet

}// end of InitComponents

public class ConsoleForJARPrograms implements KeyListener, ActionListener {

    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    int screenWidth = screenSize.width;
    int screenHeight = screenSize.height;

    String title = null;
    String text = null;

    JFrame jf = null;
    JTextArea jta = null;
    JScrollPane jsp = null;
    JMenuBar jmb = null;
    JMenu jm = null;
    JMenuItem jmi = null;

    int initialCaretPosition = 0;
    int currentCaretPosition = 0;
    boolean inputAvailable = false;

    // key codes
    int BACKSPACE = 8;
    int ENTER = 10;
    int PG_UP = 33; // do nothing for this key pressed
    int PG_DN = 34; // do nothing for this key pressed
    int END = 35;
    int HOME = 36;
    int LEFT_ARROW = 37;
    int UP_ARROW = 38; // do nothing for this key pressed
    //int RIGHT_ARROW = 39; // handled by JTextArea
    int DOWN_ARROW = 40; // do nothing for this key pressed

    int CTRL = 128;
    int A = 65; // disable ctrl-a
    int H = 72; // handle ctrl-h
    //int DELETE = 127; // handled by JTextArea

    public void actionPerformed(ActionEvent ae) {
        int cCurrPos = jta.getCaretPosition();
        jta.selectAll();
        jta.copy();
        jta.select(cCurrPos, cCurrPos);
    } // end of actionPerformed

    public void keyTyped(KeyEvent ke) {
    } // end of keyTyped

    public void keyReleased(KeyEvent ke) {
    } // end of keyReleased

    public void keyPressed(KeyEvent ke) {
        int keyCode = ke.getKeyCode();
        if ((keyCode == PG_UP) || (keyCode == PG_DN) || (keyCode == UP_ARROW) || (keyCode == DOWN_ARROW) || ((keyCode == A) && (ke.getModifiersEx() == CTRL))) {
            ke.consume();
        } else if ((keyCode == LEFT_ARROW) || (keyCode == BACKSPACE) || ((keyCode == H) && (ke.getModifiersEx() == CTRL))) {
            synchronized(this) {
                if (jta.getCaretPosition() <= initialCaretPosition) {
                    ke.consume();
                }
            } // end of synchronized block
        } else if (keyCode == HOME) {
            synchronized(this) {
                jta.setCaretPosition(initialCaretPosition);
                ke.consume();
            } // end of synchronized block
        } else if (keyCode == END) {
            synchronized(this) {
                jta.setCaretPosition(jta.getDocument().getLength());
                ke.consume();
            } // end of synchronized block
        } else if (keyCode == ENTER) {
            jta.setCaretPosition(jta.getDocument().getLength());
            synchronized(this) {
                currentCaretPosition = jta.getCaretPosition();

                // If character at initial caret position is newline then it means that the user has
                // pressed enter without enetring any other character. Also, the code gets called here
                // as soon as enter is pressed which means that the caret position (jta.getCaretPosition())
                // of the document will be incremented by 1 by the system after this code returns.
                // This means that if at initial caret position, the character is newline, then we must ignore
                // this enter and increment initial caret position by 1 and do not set inputAvailable to true.
                try {
                    String charAtInitialCaretPosition = jta.getText(initialCaretPosition, 1);
                    if ((charAtInitialCaretPosition.equals("\n")) == true) {
                        initialCaretPosition++;
                    }
                } catch (Exception e) {
                }
                /*
                debug: start
                try {
                    System.out.println("keyPressed (1): initial = " + initialCaretPosition + ", current = " + currentCaretPosition + ", System current = " + jta.getDocument().getLength());
                    String initialString = jta.getText(initialCaretPosition, 1);
                    String currentString = jta.getText(currentCaretPosition, 1);
                    System.out.println("char at initial = " + initialString + ", char at current = " + currentString);
                    if ((initialString.equals("\n")) == true) {
                        System.out.println("char at initial is newline");
                    }
                    if ((currentString.equals("\n")) == true) {
                        System.out.println("char at current is newline");
                    }
                } catch (Exception e) {
                }
                debug:end
                */

                if ((currentCaretPosition - initialCaretPosition) > 0) {
                    inputAvailable = true;
                    notifyAll();
                }
            } // end of synchronized block
        } // end of if else if
    } // end of keyPressed

    String getInputFromJTextArea(JTextArea jta) {
        int len = 0;
        String inputFromUser = "";
        while (true) {
            synchronized(this) {
                if (inputAvailable == true) {
                    len = currentCaretPosition - initialCaretPosition;

                    try {
                        inputFromUser = jta.getText(initialCaretPosition, len);
                        initialCaretPosition = currentCaretPosition;
                    } catch (Exception e) {
                        inputFromUser = "";
                        return inputFromUser;
                    } // end of outer try catch

                    /*
                    The following lines of code are not needed now.
                    if ((len == 1) && (inputFromUser.equals("\n")) == true) {
                        try {
                            wait();
                            continue;
                        } catch (Exception e) {
                        } // end of try catch
                    } else if (Character.compare(inputFromUser.charAt(0), '\n') == 0) { // matched
                        // remove first character from inputFromUser
                        inputFromUser = inputFromUser.substring(1);
                    }
                    */
                    inputAvailable = false;
                    return inputFromUser;
                } else {
                    try {
                        wait();
                        continue;
                    } catch (Exception e) {
                    } // end of try catch
                } // end of if else inputAvailable
            } // end of synchronized block
        } // end of while true
    } // end of getInoutFromJtextArea

    void outputToJTextArea(JTextArea jta, String text) {
        jta.append(text);
        jta.setCaretPosition(jta.getDocument().getLength());
        synchronized(this) {
            initialCaretPosition = jta.getCaretPosition();
        }
    } // end of outputToJTextArea

    void begin() {
        while (true) {
            outputToJTextArea(jta, "Enter some input (press enter after inputting): ");
            String input = getInputFromJTextArea(jta);
            outputToJTextArea(jta, "User input was: " + input + "\n\n");
        }
    } // end of begin

    void configureJTextAreaForInputOutput(JTextArea jta) {
        jta.addKeyListener(this);

        // remove all mouse listeners
        for (MouseListener listener : jta.getMouseListeners()) {
            //outputToJTextArea(jta, "\nRemoving mouse listener\n");
            jta.removeMouseListener(listener);
        }

        // remove all mouse motion listeners
        for (MouseMotionListener listener : jta.getMouseMotionListeners()) {
            //outputToJTextArea(jta, "\nRemoving mouse motion listener\n");
            jta.removeMouseMotionListener(listener);
        }

        // remove all mouse wheel listeners
        for (MouseWheelListener listener : jta.getMouseWheelListeners()) {
            //outputToJTextArea(jta, "\nRemoving mouse wheel listener\n");
            jta.removeMouseWheelListener(listener);
        }
    } // end of configureJTextAreaForInputOutput

    void createAndShowGUI() {
        title = "Console";
        jf = InitComponents.setupJFrameAndGet(title, screenWidth - 150, screenHeight - 100);

        jta = InitComponents.setupJTextAreaAndGet("", 1000, 100, true, true, true, false, 0, 0, 0, 0);
        configureJTextAreaForInputOutput(jta);

        jsp = InitComponents.setupScrollableJTextAreaAndGet(jta, 10, 10, screenWidth - 180, screenHeight - 180);
        jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        jf.add(jsp);
        //jf.setLocation(screenWidth / 5, screenHeight / 6);

        jmb = InitComponents.setupJMenuBarAndGet();
        jm = InitComponents.setupJMenuAndGet("Copy All to Clipboard");
        jm.setBorder(BorderFactory.createLineBorder(Color.green, 2));
        jmi = InitComponents.setupJMenuItemAndGet("Copy All to Clipboard");
        jm.add(jmi);
        jmb.add(jm);
        jmi.addActionListener(this);
        jf.setJMenuBar(jmb);

        jf.setVisible(true);
    } // end of createAndShowGUI

    public static void main(String[] args) {
        ConsoleForJARPrograms cfjp = new ConsoleForJARPrograms();
        cfjp.createAndShowGUI();
        cfjp.begin();
    } // end of main

} // end of ConsoleForJARPrograms
1

As long as the .jar is executed with java.exe, a commandline window will always show up. executing it with javaw.exe would prevent this.

for further reading: http://download.oracle.com/javase/1.4.2/docs/tooldocs/windows/java.html

Simiil
  • 2,281
  • 1
  • 22
  • 32
  • What does that mean java.exe vs javaw.exe? I'm just wanting the .jar to be double clicked. Sorry I'm still a bit new. – CaldwellYSR Oct 09 '11 at 15:12
  • oh you mean the java commmand... that requires first going into the command line and running it that way. I was hoping there was a way to double click the .jar and have it then open a command line window... because most of my friends won't know how to run the program in the command line and/or they don't want to. – CaldwellYSR Oct 09 '11 at 15:18
  • when you look into your Jre's "bin" folder, you'll see (among oithers) a java.exe and a javaw.exe. It depends on the System settings, which exe will be executed when doubleclicking an jar. Look at this question: http://stackoverflow.com/questions/394616/running-jar-file-in-windows – Simiil Oct 09 '11 at 15:20
  • So it's going to depend upon their machine settings. That's mighty unfortunate – CaldwellYSR Oct 09 '11 at 15:23
  • then you could write a bat file wich calls `java -jar yourjar.jar` – Simiil Oct 09 '11 at 15:26
0

I guess the simplest way is to write a simple shortcut for your jar file. e.g. eclipse (like the most ide's) is able to export a jar file with all necessary libraries, etc. so you just need to set the shortcut command like "java -jar filePath/file.jar" (filePath: e.g. ./bin/file.jar)

khaos
  • 1
0

One way to accomplish this is to create a .bat file with the command: "java -jar filePath/yourfile.jar" (without ""). Make sure to include the file path or else your file won't be found. Though the question was answered already, this is a simple way to do it.

MK-ULTRA
  • 3
  • 4
0

You could create your own window, using Swing or Awt, using a TextPane, the only problem... is how to input and use like the cmd should do. But you can always do this with alerts and all...

Other way, is running directly from a batch file, showing on the console.

You should consider too, make your game DIRECTLY on batch... is not a bad language to make and is present on every Windows Operating Systems.

(Hope was useful ('cause i'm new), and my english was not THAT BAD...)

0
  1. Use Launch4j and in Basic Tab give your exe name in Output file and then load a jar file in Jar Tab.
  2. Go to Header Tab and select Console.
  3. Then go to JRE tab and give the JRE version e.g 1.8.0
  4. Then click the build wrapper button (kind of setting icon)
  5. It will ask you to save a xaml file just put some random name and click save.
  6. Finally your .exe is created and you can run now.
codemyway
  • 25
  • 5
0

I found another way ... for example for project myproject with a class foo in package bar :

java -cp myproject.jar; bar.foo
THess
  • 1,003
  • 1
  • 13
  • 21
0

I wrote a little snippet which uses a similar approach to Brandon Barajas' solution. It supports Mac (untested), Linux (tested with xfce) and Windows (cmd) in one go (although you might need to customize the linux terminal commands, since there are many different ones).

https://github.com/Lartsch/java-selfconsole/

Really helpful in the following case:

  • you don't want the jar to have to be directly executed in a console
  • you can't use any custom made console / can't use any GUI library
  • you don't want to ship bridge starting files like sh, bat, ...
  • you simply want the jar to open itself in a console on double-click