2015-06-19 4 views
0

У меня очень странный сценарий, который, к сожалению, я не могу предотвратить в моем приложении Swing. Однако, когда это происходит, это имеет серьезные последствия для меня. Возможно, кто-то может помочь!Предотвращение разрыва JTextField/JDialog с повторной передачейFocus()

Базовая настройка выглядит следующим образом:

  • среды Linux.
  • Несколько JTextFields в JFrame.
  • JTextFields push through transferFocus() при нажатии клавиши Enter.
  • JDialog появляется при выходе из одного из полей, для которого требуется нажать клавишу Enter, чтобы удалить его.

ситуация, которая вызывает вопрос заключается в следующем:

  • клавишу ввода удерживается в нажатом положении в течение нескольких секунд.

Когда клавиша ввода удерживается нажатой, фокус, очевидно, пролетает через разные текстовые поля. Когда появится диалоговое окно, клавиша ввода закрывает его, в результате чего фокус будет продолжать пролетать через текстовые поля. В конце концов, через пару секунд Java разбивается. Текстовые поля немедленно перестают отвечать на нажатия клавиш - вы вообще ничего не можете вводить в них. Кроме того, все кажется нормальным - вы можете щелкнуть мышью и сосредоточиться на разных текстовых окнах, закрыть приложение и т. Д.

Я создал простой тестовый пример, который вы можете использовать для воссоздания ситуации.

фрейм:

public class TestSwing extends JFrame { 

    JTextField jtfText1, jtfText2, jtfText3; 
    TextHandler handler = null; 

    public TestSwing() { 
     super("TextField Test Demo"); 
     Container container = getContentPane(); 
     container.setLayout(new FlowLayout()); 
     jtfText1 = new MyJTextField(10); 
     jtfText2 = new MyJTextField(10); 
     jtfText3 = new MyJTextField(10); 
     container.add(jtfText1); 
     container.add(jtfText2); 
     container.add(jtfText3); 
     handler = new TextHandler(); 
     jtfText3.addActionListener(handler); 
     setSize(325, 100); 
     setVisible(true); 
    } 
    private class TextHandler implements ActionListener { 
     public void actionPerformed(ActionEvent e) { 
      JOptionPane.showConfirmDialog(null, "wait!"); 
     } 
    } 
    public static void main(String args[]) { 
     TestSwing test = new TestSwing(); 
     test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 
} 

Обычай JTextField:

public class MyJTextField extends JTextField {  
    public MyJTextField(int len) { 
     super(len); 
     addKeyListener(new KeyAdapter() { 
       public void keyPressed(KeyEvent evt) { 
       int key = evt.getKeyCode(); 
       if (key == KeyEvent.VK_ENTER) 
        transferFocus(); 
       } 
     }); 
    } 
} 

Чтобы ответить на любые возможные вопросы Спереди:

  • Ввода ключ должен использоваться для передачи фокуса.
  • Распаковка клавиши Enter происходит от пользователя, оставляющего что-то на клавиатуре (это в розничной среде, так что это часто случается).
  • Простое закрытие и перезапуск приложения на самом деле не является вариантом, поскольку в компьютер не подключена мышь. Приложение запускается автоматически при запуске, что делает этот сценарий разрушительным, так как единственным способом устранить проблему является перезагрузка машины.
  • Машины не очень мощные (обработка & памяти), что почему-то вызывает проблему намного быстрее, чем когда она воссоздана на машине разработки.

Является ли это ошибкой на Java? Может ли кто-нибудь подумать о способе предотвратить это?

Ближайший я могу добраться до предотвращения этого не происходит, поставить сон (500) вызова в JDialog (шахта продлена) до закрытия, но это на самом деле не большой фикс ...

У меня есть испытал это в JDK 1.6, 1.7 и 1.8.Хотя в более поздних версиях требуется больше времени для того, чтобы текстовые поля перестали отвечать на запросы, это все равно произойдет в конечном итоге.

Заранее благодарен!

Xandel

ответ

0

Не используйте KeyEvents. KeyEvents обычно используются в AWT. Swing имеет более новые и лучшие API для использования (в большинстве случаев). В этом случае JTextField был разработан для ответа на ActionEvent, когда нажата клавиша Enter.

Вы можете попытаться отслеживать последний раз, когда был нажат Enter, и игнорировать события, которые, как представляется, вызываются в пределах частоты повторения ОС. Моя скорость повторения составляет около 35 мс:

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

public class MyJTextField extends JTextField 
{ 
    private static long lastTime = System.currentTimeMillis(); 

    public MyJTextField(int len) 
    { 
     super(len); 
     addActionListener(new ActionListener() 
     { 
      public void actionPerformed(ActionEvent evt) 
      { 

       long diff = evt.getWhen() - lastTime; 
       System.out.println(diff); 

       if (diff > 50) 
       { 
        transferFocus(); 
       } 

       lastTime = evt.getWhen(); 
      } 
     }); 
    } 
} 
+0

Это была отличная идея! Простой, аккуратный и эффективный. Мой JDialog, к сожалению, также использует KeyListener, так как нет фактической кнопки, чтобы щелкнуть, поэтому я расширил ваше решение, чтобы иметь «системную» переменную lastTime, и применил ту же концепцию к моей реализации JDialog. – Xandel