2

標準コンソールを使用してユーザー入力を取得し、System.in および System.out からメッセージを表示するいくつかの小さなアプリケーションがあります。

ここで、これらのアプリケーションから呼び出される Swing ベースのクラスを実現したいと思います。2 つのテキスト領域を持つフレームが表示されます。 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 からデータを取得するために、メソッド troughtout を使用してSwingWorkeroutPipedoInBackgroudからScanner行を読み取り、これらの行の文字列を編集不可能な JTextArea に追加するために公開します。一方、プロンプトとして使用される JTextField からテキストを取得するためにクリックをkeyListenerチェックしVK_ENTERます。これが発生すると、System.out 自体を使用してテキストが表示され、以前の JTextArea に効果的に表示されるため、上記の SwingWorker が機能し、次に、同じテキスト行を inWriter ( PrintStreamSystem.in に関連するパイプに関連付けられたオブジェクト) に書き込んだので、元のアプリケーションに存在する Reader オブジェクトからその行を読み取ることができるはずです。

残念ながら、これは機能しないコードの唯一の部分です。実際、新しい gui コンソールを起動してからストリームを変更すると、元のアプリケーションは System.out に出力するテキストのみを表示しますが、ユーザーが書いたテキストを読みたい場合、たとえば BufferedReader または aスキャナー オブジェクトは、ストリーム内が空であるかのように何も起こりません。

これは、SwingWorker doInBackground メソッドの Scanner が原因だと思います。これは、outPipe の次の行を読み取るときに、ストリーム自体もクリーンアップするためです。この問題を解決するためのアイデアはありますか? 入力と出力を処理する新しいメソッドを作成できることはわかっていますが、この邪魔にならないアプローチを維持したいので、元のコードを編集せずに、元のアプリケーションのメイン メソッドでの GUI コンソール オブジェクトの作成の一部を行います。前もって感謝します。

更新 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");
        }
    });

}

}
4

1 に答える 1

0

私は自分で解決策を見つけました。実際、最初の投稿に投稿されたすべてのコードはほぼ正しいです。問題は、Scannerオブジェクトで行われたため、元のプログラムの System.in からの読み取りにあります (ただし、 BufferedReader も)、文字列の終了に関連しているようです。単純な呼び出しを使用して読み取るSystem.in.read()と、もちろん char ごとに正しいデータが得られるためです。どちらのScanner方法もread一方も I/O ブロッキングなので、文字列の終端に関係するものだと思います。上記のコードでわかるように、InputStream に書き込んだときに、LF および CF 文字から文字列をクリアしたため、println呼び出されたときに\r\nのみを追加する必要があります。しかし、結果の char を char ごとに読み取ると、\r\n\r\nと表示されます最後に、それを処理する正しい方法を理解できなかったとしても、文字列の末尾に関連するものでなければならないと思います。最新情報をお知らせしますが、提案やフィードバックがあれば、もちろん歓迎します。

于 2013-02-07T23:48:52.747 に答える