2

私はSwingの初心者なので、これはばかげているかもしれません。

とにかく、私はJFrameを拡張するクラスを作成し、パネル内にJTextField、JTextArea、およびJButtonが含まれています。

これはコンソール実装であると想定されているため、Enterキーまたはその横のボタンを押すと、TextFieldは入力をTextAreaに出力します。

私はこれのリスナーを作りました、そしてすべてがうまくいきます。今の私の問題は、フィールドでEnterキーを押すことを期待するメソッドをどのように作成するかです。たとえば、3行の入力が必要なメソッドがあります。最初の行はメソッドを呼び出し、2番目の行は私が何かを入力することを期待し、3番目の行はさらに入力を期待します。すべての入力が終了したら、TextAreaに何かを印刷します。

では、実際には、メソッドはリスナーが起動するのを待つ必要がありますか?誰かがこのことがどのように機能するかを説明したり、トリックを実行する回避策を教えてもらえますか?

おそらく複数行の入力で多くのメソッドを実装するので、再利用可能な方法が必要であることを覚えておいてください。前もって感謝します!

更新:これがJFrameを拡張する私のクラスです-コードは主にNetBeanで生成されたものであり、遅かれ早かれインポートステートメントで作業するようにします。方法がわからないため、まだメソッドを実装していませんが、入力が最初に正しいかどうかをチェックするコードを少し追加して(ConsoleInputAcionPerformed内)、メソッドを呼び出します(methodXと呼びましょう)。 )残りの2つの入力行が必要になります。このクラスは、main()の別のクラスから呼び出されます。

public class MainWindow extends javax.swing.JFrame {
private javax.swing.JButton EnterButton;
private javax.swing.JPanel ConsolePanel;
private javax.swing.JScrollPane ConsoleScroll;
private javax.swing.JTextArea ConsoleOutput;
private javax.swing.JTextField ConsoleInput;

public MainWindow() {
    initComponents();
}

private void initComponents() {

    ConsolePanel = new javax.swing.JPanel();
    ConsoleScroll = new javax.swing.JScrollPane();
    ConsoleOutput = new javax.swing.JTextArea();
    ConsoleInput = new javax.swing.JTextField();
    EnterButton = new javax.swing.JButton();

    setTitle("Graphical Super Console v.1.0");
    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
    setPreferredSize(new java.awt.Dimension(800, 600));

    ConsoleOutput.setColumns(20);
    ConsoleOutput.setRows(5);
    ConsoleOutput.setLineWrap(true);
    ConsoleOutput.setEditable(false);
    ConsoleOutput.setFont(new java.awt.Font("Consolas", 1, 14));

    ConsoleScroll.setViewportView(ConsoleOutput);
    ConsoleScroll.setVerticalScrollBarPolicy(javax.swing.JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

    ConsoleInput.setText("");
    ConsoleInput.requestFocusInWindow();
    ConsoleInput.setFont(new java.awt.Font("Consolas", 1, 14));
    ConsoleInput.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            ConsoleInputActionPerformed(evt);
        }
    }); 

    EnterButton.setText(">>");
    EnterButton.setFont(new java.awt.Font("Consolas", 1, 14));
    EnterButton.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            ConsoleInputActionPerformed(evt);
        }
    });

    javax.swing.GroupLayout ConsolePanelLayout = new javax.swing.GroupLayout(ConsolePanel);
    ConsolePanel.setLayout(ConsolePanelLayout);
    ConsolePanelLayout.setHorizontalGroup(
        ConsolePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(ConsolePanelLayout.createSequentialGroup()
            .addContainerGap()
            .addGroup(ConsolePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(ConsoleScroll)
                .addGroup(ConsolePanelLayout.createSequentialGroup()
                    .addComponent(ConsoleInput, javax.swing.GroupLayout.DEFAULT_SIZE, 679, Short.MAX_VALUE)
                    .addGap(18, 18, 18)
                    .addComponent(EnterButton)))
            .addContainerGap())
    );
    ConsolePanelLayout.setVerticalGroup(
        ConsolePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(ConsolePanelLayout.createSequentialGroup()
            .addContainerGap()
            .addComponent(ConsoleScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 536, Short.MAX_VALUE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
            .addGroup(ConsolePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                .addComponent(EnterButton)
                .addComponent(ConsoleInput, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
            .addContainerGap())
    );

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addComponent(ConsolePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addComponent(ConsolePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
    );

    pack();
    setVisible(true);
    ConsoleInput.requestFocus();
}
private void ConsoleInputActionPerformed(java.awt.event.ActionEvent evt) {
    printf(">"+ConsoleInput.getText()+"\n");
    ConsoleInput.setText("");
}

public javax.swing.JTextArea getConsoleOutput(){
    return ConsoleOutput;
}

public javax.swing.JTextField getConsoleInput(){
    return ConsoleInput;
}

public void printf(Object... obj){
    for(int i=0; i<obj.length; i++){
        ConsoleOutput.append(String.valueOf(obj[i]));
    }
}

}

4

5 に答える 5

1

オブザーバブルとオブザーバブル:

基本的には、あるクラスが別のクラスを監視していて、何かが発生すると、監視されているクラスであるObservableが、監視しているクラスであるObserverに通知し、何かが変更されたことを通知します。Observableには、それを実現するためのメソッドsetChanged()とnotifyObservers()があります。そして、オブザーバーは、実装されたupdate()メソッドを使用してその呼び出しをリッスンします。

これをコピーして貼り付けて実行できるように、すべてを1つのクラスにまとめました。キーを押すと、それがどのように機能するかがわかります。

//the textfield is wrapped in a class so that it can extends Observable
public class MyTextField extends Observable {

    private JTextField jTextField = new JTextField();

    //this method notifies the observers you will add   
    public void notify(Object o) {
        this.setChanged();
        this.notifyObservers(o);
    }

    public JTextField getJTextField() {
        return jTextField;
    }

}

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

// The main class that observes the swing component you tell it to
public class Controller implements Observer {

    private final JFrame jFrame = new JFrame();

    private final MyTextField myTextField = new MyTextField();

    public Controller() {

        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.pack();
        jFrame.setVisible(true);
        jFrame.add(myTextField.getJTextField());

        //here we add the Observer (Controller) to myTextField (Observable)
        myTextField.addObserver(this);

        //and the keylistener
        myTextField.getJTextField().addKeyListener(new KeyListener() {

            @Override
            public void keyTyped(KeyEvent e) {
                System.out.println("keyTyped " + e.getKeyCode());
                //now we notify our observers for real
                myTextField.notify(e.getKeyCode());
            }

            @Override
            public void keyReleased(KeyEvent e) {
                System.out.println("keyReleased " + e.getKeyCode());
                myTextField.notify(e.getKeyCode());
            }

            @Override
            public void keyPressed(KeyEvent e) {
                System.out.println("keyPressed " + e.getKeyCode());
                myTextField.notify(e.getKeyCode());
            }
        });
    }

    // this is where the event is received by the Observer 
    // from the observable.
    @Override
    public void update(Observable observable, Object object) {
        System.out.println("Notified by " + observable
                + " with object " + object);

    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Controller();
            }
        });
    }
}

I hope that is understandable and a solution to your problem :)

于 2012-09-05T22:06:58.417 に答える
0

私が考えることができる唯一のことは、現在の状態を判断できる単一のメソッドを介してフィールドからの入力を実行する必要があるということです...すなわち

public void handleFieldInput(JTextField field) {
    String text = field;
    switch (state) {
        case 0:
            // First line...maybe store the result in a List or array
            state++;
            break;
        case 1:
            // Second line...
            state++;
            break;
        case 2:
            // Third line...
            // Add contents to the text area
            state = 0;
            break;
    }
}
于 2012-09-05T20:54:40.523 に答える
0

これがあなたの解決策です:

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class Frame extends JFrame{
    JTextField t = new JTextField(20);
    JPanel p = new JPanel();

    public Frame(){
        p.add(t);
        t.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                t.setText("Hello world");
            }
        });
        add(p);
    }

    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable(){
            public void run(){
                Frame f = new Frame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.pack();
                f.setVisible(true);
            }   
        });
    }
}
于 2012-09-05T20:55:54.007 に答える
0

ユーザー入力を待っている間にメソッドをハングさせる最も簡単な方法は、おそらくテキストボックスを含むJDialogを作成することです。ユーザーがJDialogを閉じるまで、コードはそのダイアログを表示した時点を超えて実行されません。ただし、これはあなたが探している解決策のようには思えません。

ここでコードをハングさせるためにおそらくやりたいことは、waitとnotifyを使用することです。詳細については、「Javaで待機と通知を使用する方法」を参照してください。

于 2012-09-05T21:01:40.530 に答える
0

おそらく、これを思っていたのとは少し違う方法で行う必要があります。基本的に、すでに受信したすべての行の状態を維持し、すでに3行ある場合にのみ、3行を必要とするメソッドを呼び出します。一般的な考え方は次のようになります。

List<String> buffer = new ArrayList<String>();

public void actionPerformed(ActionEvent e) {
    buffer.add(getText())
    if (!expectingMoreInput()) {
        processInput(buffer);
        buffer.clear();
    }
}

したがって、特定のケースでexpectingMoreInput()は、を返すだけbuffer.size() < 3で、processInput実際には3行を必要とするメソッドを呼び出します。

それを行う別の方法は、複数のスレッドとそれらの間に行を渡すオブジェクトを使用することです。これには注意してください-スレッドの相互作用は複雑になる可能性があります。何かのようなもの:

SynchronousQueue<String> queue = new SynchronousQueue<String>();

public void actionPerfomred(ActionEvent e) {
    queue.add(getLine());
}

public void threeLineMethod() {
    String s1, s2, s3;
    try {
        s1 = queue.take();
        s2 = queue.take();
        s3 = queue.take();
    } catch (InterruptedException ex) {

    }
    // process the three lines
}

ここでは、takeがブロックされることに注意してくださいput。これはまさにあなたが望むものです。反対に、putがブロックされるtakeので、常に呼び出すスレッドがない場合はtake、イベントスレッドがブロックされ、インターフェイスがロックされます。

于 2012-09-05T21:04:45.117 に答える