2

我是 Swing 的新手,所以这可能很愚蠢。

无论如何,我创建了一个扩展 JFrame 的类,并且在面板内包含一个 JTextField、一个 JTextArea 和一个 JButton。

这应该是一个控制台实现,因此当我按下 Enter 或旁边的按钮时,TextField 会将输入打印到 TextArea。

我已经为此制作了听众,一切正常。我现在的问题是如何制作一个希望我在字段上按 Enter 的方法?例如,我有一个需要 3 行输入的方法。第一行调用方法,第二行期望我输入一些东西,第三行期望更多输入。完成所有输入后,我将一些内容打印到 TextArea。

那么实际上该方法必须等待侦听器触发还是什么?有人可以解释一下这个东西是如何工作的,或者给我一个解决方法吗?

请记住,我想要一些可重用的方式,因为我可能会使用多行输入实现很多方法。提前致谢!

更新:这是我扩展 JFrame 的类 - 代码主要是 netbean 生成的,我将确保迟早处理导入语句。我还没有实现一个方法,因为我不知道怎么做,但是希望我添加一小段代码检查输入是否正确(在 ConsoleInputAcionPerformed 内部)并调用该方法(我们称之为 methodX ) 这将需要两条输入线的其余部分。这个类是从我的 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 将通知该类 Observes,即观察者,并告诉它发生了一些变化。Observable 有方法 setChanged() 和 notifyObservers() 来完成。观察者使用实现的 update() 方法监听该调用。

我将所有内容都放在一个类中,以便您可以复制/粘贴并运行它。当你敲击一个键时,你会看到它是如何工作的。

//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();
            }
        });
    }
}

我希望这是可以理解的,并且可以解决您的问题:)

于 2012-09-05T22:06:58.417 回答
0

您可能不得不以与您希望的有所不同的方式执行此操作。基本上你保持你已经收到的所有行的状态,只有当你已经有三行时,然后调用需要三行的方法。一般的想法是这样的:

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

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

因此,对于您的特定情况,expectingMoreInput()只需 return buffer.size() < 3,并且processInput实际上会调用需要三行的方法。

另一种方法是使用多个线程和一个在它们之间传递线路的对象。请注意这一点 - 线程交互可能会变得复杂。就像是:

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 回答
0

在等待用户输入时使方法挂起的最简单方法可能是创建一个带有文本框的 JDialog。在用户关闭 JDialog 之前,您的代码不会运行超过显示该对话框的点。然而,这似乎不是您正在寻找的解决方案。

你可能想要在这里让你的代码挂起是使用等待和通知。有关更多信息,请参阅如何在 Java 中使用等待和通知?.

于 2012-09-05T21:01:40.530 回答
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 回答