我有几个小应用程序,它们使用标准控制台来检索用户输入和显示消息 troughtout System.in 和 System.out。
现在我想实现一些从这些应用程序调用的基于 Swing 的类,它显示一个带有 2 个文本区域的框架,一个用于输入(与 System.in 相关联),另一个(不可编辑)显示消息(因此相关联到 System.out)。实际上我已经实现了所有,(实际上创建一个简单的基于摆动的 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
方法troughtout a从outPipeScanner
中读取行并发布它们,以便将这些行字符串附加到不可编辑的JTextArea 中。同时keyListener
检查VK_ENTER
点击以从用作提示的 JTextField 中获取文本,一旦发生这种情况,文本将使用 System.out 本身显示,并且它有效地出现在先前的 JTextArea 中,因此上述 SwingWorker 有效,并且然后我在 inWriter(PrintStream
与 System.in 相关的管道关联的对象)中写入了同一行文本,因此该行应该可以从原始应用程序中存在的 Reader 对象中读取。
不幸的是,这是代码中唯一不起作用的部分。事实上,一旦我启动新的 gui 控制台,然后更改流,原始应用程序将只显示它在 System.out 上打印的文本,但是当它想要读取用户编写的文本时,例如 troughtout 一个 BufferedReader 或一个Scanner 对象,没有任何反应,好像 in 流是空的。
我认为这是由于 SwingWorker doInBackground 方法中的 Scanner 造成的,因为当它读取 outPipe 上的下一行时,它也会清理流本身。有什么想法可以摆脱这个问题吗?我知道我可以编写新的方法来处理输入和输出,但我想保持这种非侵入性的方法,所以在不编辑原始代码的情况下,在原始应用程序主方法中创建 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");
}
});
}
}