2 votes

Méthode d'écoute

Je suis un novice en matière de Swing, alors il se peut que ce soit stupide.

Quoi qu'il en soit, j'ai créé une classe qui étend JFrame et un panneau contenant un JTextField, un JTextArea et un JButton.

Il s'agit d'une mise en œuvre de la console, de sorte que le champ textuel imprime les données saisies dans la zone de texte lorsque j'appuie sur la touche Entrée ou sur le bouton situé à côté.

J'ai créé le listener pour cela et tout fonctionne bien. Mon problème maintenant est de savoir comment créer une méthode qui s'attend à ce que j'appuie sur la touche Entrée du champ ? Par exemple, j'ai une méthode qui a besoin de 3 lignes de saisie. La première ligne appelle la méthode, la deuxième attend que je saisisse quelque chose et la troisième attend une autre saisie. Une fois que toutes les entrées sont terminées, j'imprime quelque chose dans le TextArea.

En pratique, la méthode devra-t-elle attendre qu'un Listener se déclenche ou quoi ? Quelqu'un peut-il m'expliquer comment cela peut fonctionner ou me donner une solution de contournement qui fonctionne ?

Gardez à l'esprit que je veux un moyen réutilisable parce que je vais probablement implémenter beaucoup de méthodes avec une entrée multi-ligne. Merci d'avance !

Mise à jour : voici ma classe qui étend JFrame - le code a été généré par netbean principalement, je vais m'assurer de travailler sur les déclarations d'importation tôt ou tard. Je n'ai pas encore implémenté de méthode car je n'ai aucune idée de comment le faire, mais attendez-vous à ce que j'ajoute un petit bout de code vérifiant si l'entrée est correcte au début (à l'intérieur de la ConsoleInputAcionPerformed) et appelle la méthode (appelons-la methodX) qui aura besoin du reste des deux lignes d'entrée. Cette classe est appelée depuis une autre classe dans mon 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]));
    }
}

}

1voto

fonZ Points 1522

L'observateur et l'observable :

L'idée de base est qu'une classe en observe une autre et que, lorsque quelque chose se produit, la classe observée, l'Observable, notifie la classe qui observe, l'Observer, et lui indique que quelque chose a changé. L'Observable a des méthodes setChanged() et notifyObservers() pour accomplir cela. Et l'Observateur écoute cet appel avec la méthode update() implémentée.

J'ai tout mis dans une seule classe pour que vous puissiez faire un copier/coller et l'exécuter. Lorsque vous appuyez sur une touche, vous verrez comment cela fonctionne.

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

J'espère que c'est compréhensible et une solution à votre problème :)

0voto

MadProgrammer Points 161522

La seule chose à laquelle je peux penser est que vous devez faire passer l'entrée du champ par une méthode unique qui peut déterminer l'état actuel...c'est-à-dire

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;
    }
}

0voto

Branislav Lazic Points 4665

Voici votre solution :

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

0voto

Accipheran Points 1283

Le moyen le plus simple de faire en sorte qu'une méthode se bloque en attendant la saisie de l'utilisateur est probablement de créer un JDialog contenant une zone de texte. Tant que l'utilisateur ne ferme pas le JDialog, votre code ne s'exécutera pas au-delà du moment où vous affichez cette boîte de dialogue. Cependant, cela ne semble pas être la solution que vous recherchez.

Ce que vous voulez probablement faire ici pour que votre code soit suspendu est d'utiliser wait et notify. Pour plus d'informations, voir Comment utiliser wait et notify en Java ? .

0voto

Joe K Points 4990

Vous devrez probablement faire ça un peu différemment de ce que vous aviez espéré. En gros, vous maintenez un état de toutes les lignes que vous avez déjà reçues, et seulement lorsque vous avez déjà trois lignes, vous appelez la méthode qui nécessite trois lignes. L'idée générale est la suivante :

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

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

Donc, pour votre cas spécifique, expectingMoreInput() retournerait simplement buffer.size() < 3 et processInput appellerait en fait la méthode qui nécessite trois lignes.

L'autre façon de procéder serait d'utiliser plusieurs threads et un objet pour faire passer les lignes entre eux. Soyez prudent avec cela - les interactions entre les threads peuvent devenir compliquées. Quelque chose comme :

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
}

Notez qu'ici, take bloquera sur put ce qui est exactement ce que vous voulez. Le revers de la médaille est que put bloquera sur take donc si vous n'avez pas un fil qui appelle en permanence take le fil d'événement se bloquera et l'interface sera verrouillée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X