当前位置: 首页 > 知识库问答 >
问题:

用java创建扩展基于提示的应用程序的独立gui控制台

刘和玉
2023-03-14

我有几个小应用程序,它们使用标准控制台来检索用户输入,并显示out、system.in和system.out中的消息。

现在我想实现一些从这些应用程序调用的基于Swing的类,它显示一个有两个文本区域的框架,一个用于输入(因此与System.in相关联),另一个(不可编辑)显示消息(因此与System.out相关联)。实际上我已经实现了all,(实际上创建一个简单的基于swing的gui并从event dispatcher线程启动它并不那么复杂,将all导出为jar并将其作为库包含在原始项目中也是如此)。到目前为止,我遇到的唯一问题是将标准的System.in和System.out交换到一些与2JTextarea相关联的自定义的问题。实际上,我在网上检查了一些解决方案,最后得到了以下几行代码:

我使用2个PipedInputStream和一个printwriter:

    private final PipedInputStream inPipe = new PipedInputStream(); 
    private final PipedInputStream outPipe = new PipedInputStream(); 
    private PrintWriter inWriter;

然后我交换溪流

    System.setIn(inPipe); 
    System.setOut(new PrintStream(new PipedOutputStream(outPipe), true)); 
    inWriter = new PrintWriter(new PipedOutputStream(inPipe), true); 

为了从outPipe中检索数据,我使用SwingWorker,其doinbackgroud方法通过扫描器从outPipe中读取行并发布它们,以便在不可编辑的Jtextarea中追加这些行字符串。同时,KeyListener检查vk_enter单击,以便从用作提示符的JTextField中获取文本,一旦发生这种情况,文本将使用System.out本身显示,并且它实际上显示在前面的JTextArea中,因此上面描述的SwingWorker工作,然后我在inWriter中写入了相同的文本行(PrintStream对象关联到与System.in相关的管道),因此可以从原始应用程序中存在的Reader对象中读取该行。

不幸的是,这是代码中唯一不起作用的部分。实际上,一旦我启动了新的gui控制台,然后更改流,原始应用程序将只显示它在System.Out上打印的文本,但是当它想读取用户写入的文本时,例如从BufferedReader或Scanner对象读取,什么也不会发生,就像in流是空的一样。

我认为这是由于SwingWorker doInBackground方法中的扫描器,因为当它读取outPipe上的下一行时,它也会清理流本身。有什么办法可以解决这个问题吗?我知道我可以编写处理输入和输出的新方法,但我希望保留这种非侵入性的方法,因此无需编辑原始代码,在原始应用程序main方法中创建gui控制台对象就可以了。提前谢了。

更新1

public class Console extends JFrame implements KeyListener 
{

private JTextField prompt;
private JTextArea log;


private final PipedInputStream inPipe = new PipedInputStream(); 
private final PipedInputStream outPipe = new PipedInputStream(); 

private PrintWriter inWriter;


public Console(String title)
{
    super(title);

    System.setIn(inPipe); 

    try 
    {
        System.setOut(new PrintStream(new PipedOutputStream(outPipe), true)); 
        inWriter = new PrintWriter(new PipedOutputStream(inPipe), true); 
    }
    catch(IOException e) 
    {
        System.out.println("Error: " + e);
        return;
    }

    JPanel p = new JPanel();
    p.setLayout(null);
    log = new JTextArea();
    log.setEditable(false);
    log.setBounds(10, 10, 345, 250);
    p.add(log);
    prompt = new JTextField();
    prompt.setBounds(10, 270, 356, 80);
    prompt.addKeyListener(this);
    p.add(prompt);

    getContentPane().add(p);

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setVisible(true);
    setSize(392, 400);
    setLocationRelativeTo(null);

    (new SwingWorker<Void, String>() 
    { 
        protected Void doInBackground() throws Exception 
        { 
            Scanner s = new Scanner(outPipe);
            while (s.hasNextLine()) 
            {
                String line = s.nextLine();
                publish(line);
            }
            return null; 
        } 
        @Override 
        protected void process(java.util.List<String> chunks)
        { 
            for (String line : chunks) 
            {
                if (line.length() < 1)
                    continue;
                log.append(line.trim() + "\n"); 
            }
        } 
    }).execute(); 


}
    public void execute() 
{
    String text = prompt.getText();
    prompt.setText("");
    System.out.println(text); 
    inWriter.print(text.trim().replaceAll("\r\n", ""));
}


@Override
public void keyPressed(KeyEvent e)
{
    if (e.getKeyCode() == KeyEvent.VK_ENTER)
        execute();
}

@Override
public void keyReleased(KeyEvent e)
{
    if (e.getKeyCode() == KeyEvent.VK_ENTER)
        execute();

}

@Override
public void keyTyped(KeyEvent e)
{
    if (e.getKeyCode() == KeyEvent.VK_ENTER)
        execute();

}

// this is the method called from the original application
public static void setConsole(final String title) 
{
    EventQueue.invokeLater(new Runnable()
    {
        public void run()
        {
            new Console(title);
            //System.out.println("somewhat");
        }
    });

}

}

共有1个答案

萧允晨
2023-03-14

我自己找到了解决方案,实际上第一篇文章中发布的所有代码几乎都是正确的,问题在于从系统中读取。在最初的程序中,因为它是用scanner对象完成的(但我也用BufferedReader测试了它),所以它似乎与字符串终止有关,因为如果我使用简单的system.in.read()调用读取,我得到了正确的数据,当然是逐字符的。因为scanner方法和read方法都是I/O阻塞,所以我认为这与字符串的终止有关。因为当我在InputStream上编写它时,我从任何LF和CF字符中清除了字符串,正如您在上面的代码中所看到的那样,所以当调用println时,只应该追加一个\r\n。但是一个字符一个字符地读结果,我看到\r\n\r\n在结尾,所以我想它应该是与字符串结尾有关的东西,即使我不能找到处理它的正确方法。我会随时更新你的信息,但如果你有建议和/或反馈,他们显然是受欢迎的。

 类似资料:
  • 问题内容: 如何使用Maven创建桌面(独立/ Swing)应用程序? 我正在使用Eclipse 3.6。 问题答案: 创建一个Maven项目,如下所示: 将以下条目添加到您的pom文件中: 将项目作为Maven项目导入到Eclipse,然后作为Java应用程序运行。

  • 我正在试图弄清楚如何构建一个Spring Boot独立应用程序。当然,要让东西自动连线需要一些初始的上下文起点。如果我只是尝试自动生成一个类来运行一个作业,那么即使我将它设置为静态,它也是空的。 有没有办法在一个独立的非Web应用程序中使用Spring@Services? 因此,首先将静态JobRunnerService连接到运行MyApplication的主程序,JobRunner(Servic

  • 问题内容: 所有, 我已经用Java编写了基于命令行的PhoneBook应用程序。该应用程序基本上会询问用户的一些详细信息,例如姓名,年龄,地址和电话号码,并将它们存储在文件中。其他操作包括按名称,电话号码等查找电话簿。所有详细信息都通过控制台输入。 我正在尝试为我已实现的每个功能编写JUnit测试用例,但无法弄清楚如何将实现代码重定向到我的JUnit测试方法中的某个东西,当我的实际代码停止供用户

  • 请帮帮我,我用两个外部jar文件开发了一个简单的应用程序。在清理和构建的同时,它为应用程序和dist目录中的库文件夹创建了一个jar文件。当我尝试作为jar执行时,它执行得很完美

  • 问题内容: 我想在nodejs中建立一个代码编辑器。有一些选项,例如使用Express Server显示编辑器并在后端执行代码。但这需要浏览器。因此,我正在寻找可以为Windows平台提供独立GUI的节点模块。 问题答案: 有两种不同的选择,具体取决于您要如何进行。 选项1: 使用QT或GTK绑定之类的东西来制作更传统的GUI应用程序。这些选项通常只是Node绑定到GTK和QT公开的C / C +

  • 问题内容: 我正在考虑开发由两部分组成的桌面应用程序: 用户界面(例如Java应用) 后端Node.js服务器 2个部分通过插座连接。不要问为什么我知道这很奇怪。 我将希望能够为客户提供带有安装程序的应用程序。我不希望用户必须自己安装Node.js。 有没有一种方法可以独立安装Node.js服务器,即无需在系统上全局安装Node.js。 对于任何(Windows,Linux,Mac OS X …)