Метод setText в JTextField не работает из KeyListener - PullRequest
2 голосов
/ 23 сентября 2011

Я озадачен тем, почему JTextField, похоже, не просто «очищается» с помощью метода setText (""), когда он исходит из KeyListener.Он отлично работает с ActionListener, за исключением того, что, что наиболее удивительно, если метод KeyListener пытается вызвать метод ActionListener, с фиктивным событием action (созданным на лету как простой тест), он все равно оставляет напечатанный текст на месте.

Другими словами, когда вы запустите его из командной строки, если вы введете, например, «3» в поле, вы увидите, что метод setText («test») не уничтожает 3, как я и ожидал, а пожелал, а скорее оставил его на месте.Затем вы увидите «test3» на дисплее.Я отметил эту строку с комментарием.Нажав на JButton, вы стираете текст правильно.JButton и JLabel будут корректно менять текст.но JTextField не будет.Если вы затем нажмете кнопку, вы увидите, что событие action корректно очищает JTextField.Теперь, если вы переключаете закомментированную строку, вы можете увидеть попытку вызова метода actionPerformed из метода KeyTyped !!!И все же, если вы введете «3» в текстовое поле, оно не будет уничтожено.Я ожидал бы, что метод setText ("") очистит его, чего не будет.И это даже тогда, когда метод keyTyped () вызывает тот же метод actionPerformed (), что и JTextButton.

Мотивация здесь может немного помочь.Мне нужно перехватить одну конкретную горячую клавишу, которая очистит JTextField в тот момент, когда он печатается, как если бы вы нажали кнопку «очистить».И это, похоже, не работает.

Я не так много делал с Swing раньше, но это довольно озадачивает.

Мой код SSCCE следующий:

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

class P2 implements KeyListener, ActionListener
{
  JTextField fld;
  JButton btn;
  JLabel  lbl;

  P2()
  {
    JFrame frm = new JFrame("Test");
           fld = new JTextField(10);
    JPanel pnl = new JPanel();
           btn = new JButton("Clear it out");
           lbl = new JLabel("This is a test");

    fld.addKeyListener(this);

    btn.addActionListener(this);

    frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frm.setSize(400,400);
    frm.setLayout(new FlowLayout() );
    pnl.add(fld);
    pnl.add(btn);
    pnl.add(lbl);
    frm.getContentPane().add(pnl);
    frm.setVisible(true);
  }
  public void keyPressed(KeyEvent ke) {}
  public void keyReleased(KeyEvent ke) {}
  public void keyTyped(KeyEvent ke)
  {
     System.out.println("got a pressed key");

//this is the setText method that ought to wipe clean the field comments:
    this.fld.setText("test");
    this.btn.setText("try again");
    this.lbl.setText("got a presseed key");


//toggle this comment to see the invocation of the action event:
//    this.actionPerformed(new ActionEvent( new Object(), 2, "test")  );

  }
  public void actionPerformed(ActionEvent ae)
  {
     fld.setText("");
     fld.selectAll();
  }
  public static void main(String[] args)
  {
    SwingUtilities.invokeLater
    (
      new Runnable()
      {
        public void run()
        {
          new P2();
        }
      }
    );
  }
}

Ответы [ 2 ]

2 голосов
/ 23 сентября 2011

Вот фрагмент кода, использующий привязки клавиш для стирания всего текста при нажатии «a», реализованный для использования действий, уже зарегистрированных в карте действий поля (обратите внимание, что вам все еще нужно заключить код в SwingUtilities.invokeLater - как уже Говардпредложено - это гарантирует его обработку после внутренней обработки полей)

    JTextField normal = new JTextField("just a normal field", 10);
    final Action selectAll = normal.getActionMap().get("select-all");
    final Action cut = normal.getActionMap().get("cut-to-clipboard");
    Action combine = new AbstractAction() {

        @Override
        public void actionPerformed(final ActionEvent e) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    selectAll.actionPerformed(e);
                    cut.actionPerformed(e);

                }
            });
        }

    };
    normal.getActionMap().put("magic-delete-all", combine);
    normal.getInputMap().put(KeyStroke.getKeyStroke("A"), "magic-delete-all");
2 голосов
/ 23 сентября 2011

Это связано с тем, что поле KeyEvent будет обработано полем после того, как ваш KeyListener был запущен. Вы можете обойти это, потребляя событие через

ke.consume();

внутри вашего метода keyTyped.

В зависимости от ваших требований другой способ заключался бы в инкапсуляции вызовов очистки в SwingUtilities.invokeLater, которые будут обрабатываться после вашего текущего события, и, таким образом, очищать поле после его обновления.

...