如何使我的Java应用程序打开控制台/终端窗口?

15

有没有办法制作一个可执行的 .jar 文件,并且双击后可以打开命令行?

我正在做一个基于文本的冒险游戏。现在它只是一个迷宫和房间。最终它会更大,更深入但现在我只想把基本结构搭建好。为了实现这个功能,我一直在使用 System.out.printf 命令和 java.util.Scanner 来获取输出和输入。到目前为止,一切都运作得非常顺利,但我意识到当我尝试将其发送给其他不知道如何或不想从命令行运行程序的人时,我将遇到问题。

13个回答

21

在我寻找答案时,我找到了这个,并最终写下了以下内容:

/**
 * 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");
        }
    }
}

我不确定我的回答是否仍然相关,但你可以自由地使用它,只需保留o/中的评论。

唯一的缺陷是程序完成后cmd窗口仍会保持打开状态。

用法:将此类放置在与您的主类相同的包中,并将其设置为主类,如果没有打开命令提示符窗口,则会打开一个窗口,或者如果已经打开了一个窗口,则会启动主类。 jar文件的名称/位置是自动的。设计用于Windows,但如果您想要其他系统的版本,请给我发消息,我会进行修改。(我可以进行操作系统检测,但我懒得这样做,我只是为了向使用Windows的教授提交双击jar文件而创建此文件)。


您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - mk7
@mk7 你可能忘记替换“THEMAINCLASSNAMEGOESHERE”为你项目中预期的主类名了,如果没有,请给我完整的错误信息。 - Brandon Barajas
已经替换了那个文件,还有上面两行的另一个文件。错误信息为:“无法访问jar文件C:/eclipse/workspace/TestConsole/bin/”。我尝试切换到另一个工作区,但在cmd提示窗口仍然显示相同的错误信息。我使用的是Eclipse Mars和Java SDK 1.8u60。 - mk7
1
哦,我想我现在可能知道发生了什么。你是在尝试使用Eclipse的本地环境运行它吗?你需要先将其编译成一个jar文件(以此作为主类进行编译),然后这个jar文件就可以双击运行了(在Eclipse中不需要像这样的脚本,因为它会为你创建一个终端环境)。 - Brandon Barajas
打开一个cmd提示窗口并不是很有用。每个人都可以轻松地在Eclipse控制台上打印日志语句(使用java.util.logging.Logger)。但是,如何在运行时将相同的语句输出到此cmd提示窗口? - mk7
显示剩余7条评论

5
如果您需要完全控制,可以在Swing中实现一个控制台窗口来执行您现在的操作。
如果无法打开该窗口(如果是无头模式)或用户在命令行上请求打开它,则只需默认使用当前行为。

1
当我提出这个问题时,我对swing一无所知。经过调查,我成功地创建了一个与Scanner无关的东西,而是使用JTextArea和JTextField来获取输入和输出。它非常有效,所以感谢您的答案。 - CaldwellYSR
“Console window”是什么意思?你是指带有JTextArea的窗口,像控制台一样工作,还是指实际的命令行窗口,例如Windows中的cmd? - carloswm85
@carloswm85 一个Swing窗口。我不知道是否可以使用Windows特定的API调用来打开命令行窗口。 - Thorbjørn Ravn Andersen

4

双击一个jar文件会使用你的操作系统中关联的应用程序打开它。默认情况下,javaw[.exe]通常与jar文件相关联。这是在没有终端窗口的情况下运行的二进制文件。如果要在双击时看到终端,则需要将java[.exe]二进制文件与jar文件相关联。


2

或者您可以提供一个 .sh 或 .bat 文件,它将打开终端并调用您的 Java 代码。


1
所以这是我的解决方案,我使用了@Brandon Barajas的代码并进行了修改。它创建了一个批处理文件,可以自行启动程序。
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...
    }
}

如果您想在“exit”打印之前添加writer.println("pause");,以便在程序完成后保持窗口打开状态,则需要按ENTER键关闭窗口。请注意,不要删除HTML标记。

1

这是什么意思java.exe与javaw.exe?我只想让.jar文件双击打开。抱歉,我还有点新手。 - CaldwellYSR
哦,你的意思是Java命令...那需要先进入命令行并以那种方式运行它。我希望有一种方法可以双击.jar文件,然后打开一个命令行窗口...因为我的大多数朋友不知道如何在命令行中运行程序,或者他们不想这样做。 - CaldwellYSR
当您查看JRE的“bin”文件夹时,您会看到(其中之一)是java.exe和javaw.exe。取决于系统设置,双击jar文件时将执行哪个exe。请参考此问题:https://dev59.com/OXRC5IYBdhLWcg3wJNqf - Simiil
所以这将取决于他们的机器设置。这真是太不幸了。 - CaldwellYSR
然后,您可以编写一个批处理文件,调用 java -jar yourjar.jar - Simiil

1
你可以使用这个程序。这个程序为JAR程序创建一个控制台(当通过双击运行JAR程序时)。
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

0

我找到了另一种方法...例如,对于包bar中的类foo的项目myproject:

java -cp myproject.jar; bar.foo

0
一种实现这个的方法是创建一个 .bat 文件,命令为:“java -jar filePath/yourfile.jar”(不用引号)。确保包含文件路径,否则文件将无法找到。 虽然问题已经被回答了,但这是一个简单的方法。

0

你可以使用Swing或Awt创建自己的窗口,使用TextPane,唯一的问题是如何像cmd一样输入和使用。但你总是可以用警报和其他方式来解决这个问题...

另一种方法是直接从批处理文件中运行,在控制台上显示。

你也应该考虑直接在批处理中制作游戏...这不是一个坏语言,并且存在于每个Windows操作系统中。

(希望这对你有用(因为我是新手),而且我的英语也不是那么糟糕...)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接