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

时间:2013-02-06 10:55:18

标签: java swing user-interface stream console

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

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

我使用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方法输出Scanner来读取outPipe中的行并发布它们以附加这些行在一个不可编辑的JTextArea中。 同时keyListener检查VK_ENTER点击以便从JTextField获取文本作为提示,一旦发生这种情况,文本将使用System.out本身显示,并且它有效地出现在之前的JTextArea,因此上面描述的SwingWorker工作,然后我在inWriter中编写了相同的文本行(与System.in相关的管道关联的PrintStream对象),因此该行应该可以从中读取原始应用程序中存在的Reader对象。

不幸的是,这是代码中唯一不起作用的部分。实际上,一旦我启动了新的gui控制台,然后更改了流,原始应用程序将只显示它在System.out上打印的文本,但是当它想要读取用户写入的文本时,例如,输出BufferedReader或者扫描程序对象,没有任何反应,就好像在流中是空的。

我认为这是由于SwingWorker doInBackground方法中的Scanner,因为当它读取outPipe上的下一行时,它也会清除流本身。有什么想法摆脱这个问题?我知道我可以编写处理输入和输出的新方法,但我想保留这种非侵入式方法,因此无需编辑原始代码,在原始应用程序main方法中创建gui Console对象的一部分。提前致谢。

更新1

这是Console类,一切都在这里完成

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 个答案:

答案 0 :(得分:0)

我自己找到了解决方案,实际上第一篇文章中发布的所有代码几乎都是正确的,问题在于原始程序中System.in的读取,因为它是用Scanner完成的对象(但我也用BufferedReader对它进行了测试)似乎它与字符串终止有关,因为如果我通过简单的System.in.read()调用读取,我得到了正确的数据,当然是char的字符。由于Scanner方法和read都是I / O阻塞,我认为它与字符串的终止有关。因为当我在InputStream上写它时,我清除了任何LF和CF字符串中的字符串,正如您在上面的代码中看到的那样,所以当调用println时只有 \ r \ n 应该追加。但是通过char读取结果char我最后看到 \ r \ n \ r \ n ,所以我想它应该是与字符串结尾相关的东西,即使我无法弄清楚正确的处理方式。我会通过更新来告诉你,但是如果你有建议和/或反馈,他们显然会受到欢迎。