System.out.printlnからスイングに移行しようとしているJavaの見習い

ついに私の古いコンソールプログラムをSwingに移行しようとしています。この目的のために、JFrameの代わりに拡張できるConsoleFrameクラスを作成しようとしています。これにより、古いコードとSwingをできるだけ簡単にインターフェイスできるようになります。 out(String)は動作しているように見えますが、inln()は私に困惑しています。

//Imports not included
public class ConsoleFrame extends JFrame
{
    protected JTextField in;
    protected JTextArea out;

    public ConsoleFrame(){
        this("Console Frame", 80, 10);
    }
    public ConsoleFrame(int cols){
        this("Console Frame", cols, 10);
    }
    public ConsoleFrame(int cols, int rows){
        this("Console Frame", cols, rows);
    }
    public ConsoleFrame(String title){
         this(title, 80, 10);
    }
    public ConsoleFrame(String title, int cols, int rows){
        in = new JTextField();
        in.setEditable(true);
        in.setColumns(cols);

        out = new JTextArea();
        out.setEditable(false);
        out.setColumns(cols);
        out.setRows(rows);
        out.setWrapStyleWord(true);

        setTitle(title);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        add(in, BorderLayout.PAGE_END);
        add(out, BorderLayout.PAGE_START);
        pack();
    }

    protected void out(String o) {
        out.append(o);
    }
    protected void outln(String o) {
            out(o + BIO.$ln);    //BIO.$ln == System.getProperty("line.separator")
    }

    /*
     * This is supposed to halt execution until the user presses enter, then return the text entered in the JTextField named in.
     */
    protected String inln() {
        in.setEnabled(true);
        KeyListener enter = new KeyListener() {
            @Override
            public void keyTyped(KeyEvent paramKeyEvent) {
                if(paramKeyEvent.getKeyCode() == KeyEvent.VK_ENTER) {
                     if(in.hasFocus()) {
                         in.setEnabled(false);
                     }
                }
            }
            @Override public void keyPressed(KeyEvent paramKeyEvent) {}
            @Override public void keyReleased(KeyEvent paramKeyEvent) {}    
        };
        in.addKeyListener(enter);
        while(true){    //This loop is intended to interrupt flow until in.isEnabled()==false, which will only happen when the enter key is typed.
            if(in.isEnabled()==false){
                String result = in.getText();
                in.setText("");
                in.setCaretPosition(0);
                this.removeKeyListener(enter);
                in.setEnabled(true);
                return result;
            }
        }
    }
}

テスタープログラム:

public class Tester extends ConsoleFrame
{
    public static void main(String[] args) {
        new Tester();
    }
    public Tester() {
        super("Test", 60, 30);
        out(inln());
    }
}
0

4 答え

あなたの問題を解決するかどうかは分かりませんが、KeyListnerを使用すべきではありません。

JTextFieldは、Enterキーを処理するためにActionListenerを使用するように設計されています。

2
追加された
aaaahあなたが正しいです、私は+1を参照してください
追加された 著者 mKorbel,
私はこれについてどうやって行くのですか?私はSwingにとって非常に新しいです。 instanceofとKeyEventへのキャストで何か、多分?
追加された 著者 Matt G,
Swingの基礎については、 Swingチュートリアルから始めてください。 アクションリスナーの作成方法のセクションは、開始するのに適しているかもしれません。
追加された 著者 camickr,
コンソール も便利です。
追加された 著者 trashgod,

デバッグのビットは、キーコードが常に0x0であることを示しています。 keyTyped を次のコードに置き換えると動作します。

public void keyTyped(KeyEvent paramKeyEvent) {
    if (paramKeyEvent.getKeyChar() == '\n') {
        if(in.hasFocus()) {
            in.setEnabled(false);
        }
    }
}

EDIT: I'm not saying this is a solution I'm overly happy with, but it seems to do the trick.

1
追加された
奇妙なことに、それは私がDebugパースペクティブでステップ実行したときに動作するように見えますが、通常は実行しません。
追加された 著者 Matt G,

のテキストフィールドではなく、 keyListener をフレームに追加します。したがって、イベントは常にテキストフィールドに取り込まれ、フレームまでは伝播されません。これがイベントを受け取っていない理由です。

0
追加された
編集されましたが、動作しているようには見えません。私はプログラムを実行し、 "こんにちは"と入力し、Enterキーを押します。何も起こらないようです。 のテキストは同じままで、クリアされず、出力には何も表示されません
追加された 著者 Matt G,

その inln コードは私にとって魅力的です。より堅牢にするには:

  • イベントのディスパッチスレッドとは別のスレッドで実際のプログラムが実行されるようにコードを変更します(これが既に正しいかどうかはわかりません)。テストプログラムから呼び出されたときに SwingUtilities.isEventDispatchThread はfalseを返すはずです。

  • 出力メソッドで SwingUtilities.invokeLater を使用すると、実際の出力はイベントディスパッチスレッド上で非同期に発生します。 inln()で、同期と SwingUtilities.invokeAndWait を使用してキーリスナーを初期化します(または ActionListener をすでに述べた)。入力を待っている間ビジー待機ループの代わりに Object.wait() Object.notify()を使用します(ラップトップのバッテリーはそれに感謝します)。 100%CPU使用率を表示しなくなるタスクマネージャ)。


申し訳ありませんが、あなたのための(テスト済みで動作している)コードは次のとおりです:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ConsoleFrame extends JFrame
{
    private Object lock = new Object();
    private String enteredText = null;

    protected JTextField in;
    protected JTextArea out;

    public ConsoleFrame(){
        this("Console Frame", 80, 10);
    }
    public ConsoleFrame(int cols){
        this("Console Frame", cols, 10);
    }
    public ConsoleFrame(int cols, int rows){
        this("Console Frame", cols, rows);
    }
    public ConsoleFrame(String title){
         this(title, 80, 10);
    }
    public ConsoleFrame(String title, int cols, int rows){
        in = new JTextField();
        in.setEditable(true);
        in.setColumns(cols);

        ActionListener enter = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                in.setEnabled(false);
                synchronized(lock) {
                    enteredText = in.getText();
                    lock.notifyAll();
                }
                in.setText("");
            }
        };
        in.addActionListener(enter);

        out = new JTextArea();
        out.setEditable(false);
        out.setColumns(cols);
        out.setRows(rows);
        out.setWrapStyleWord(true);

        setTitle(title);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        add(in, BorderLayout.PAGE_END);
        add(out, BorderLayout.PAGE_START);
        pack();
    }

    protected void out(final String o) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                out.append(o);
            }
        });
    }

    protected void outln(String o) {
            out(o + System.getProperty("line.separator"));
    }

    /*
     * This is supposed to halt execution until the user presses enter, then return the text entered in the JTextField named in.
     */
    protected String inln() {
        SwingUtilities.invokeLater(new Runnable() { 
            @Override
            public void run() {
                in.setEnabled(true);
            }
        });
        synchronized(lock) {
            enteredText = null;
            while (enteredText == null) {
                try {
                    lock.wait();
                } catch (InterruptedException ex) {}
            }
            return enteredText;
        }
    }
}
0
追加された
私は経験が不足しています。私はスイングをすることはできません。私はもっ​​と経験豊かになるように修正しようとしますが、今はそれが私の能力を超えています。
追加された 著者 Matt G,
Redditの礼儀で、あなたが言及している問題に対処するソリューションを見つけました。CountDownLatchは、同期の学習を開始するのに適したエントリポイントであるはずです。
追加された 著者 Matt G,
私の答えに(テスト済みで働く)コードを追加しました。お役に立てれば。
追加された 著者 mihi,