2011-12-02 53 views
1

我有一个Swing程序,它根据某些文本字段的内容和一对单选按钮(在按钮组中)的设置进行搜索。程序会自动搜索某些文本字段何时失去焦点。当失去焦点事件通过单击其中一个单选按钮触发时,问题就出现了。在单选按钮被选中()值更改之前,文本字段上的丢失焦点事件将得到处理,因此搜索将使用“错误”(即旧的)参数完成,而不是基于电台新设置的参数纽扣。如何等待单选按钮在丢失的焦点事件中被选中

我尝试使用我自己的invokeWhenIdle方法(如下所示)在事件队列稳定后运行搜索来调用搜索,但它仍然使用单选按钮的旧设置。

我唯一的工作解决方案是在运行搜索之前延迟250毫秒失去焦点事件,以便单选按钮有时间更改。这可以工作,但它会让UI显得呆滞。

有什么更好的点子?

public static void invokeWhenIdle(final int a_max_retry, final Runnable a_runnable) { 
    if (a_max_retry <= 0) { 
    throw new IllegalStateException("invokeWhenIdle: Could not run " + a_runnable); 
    } 

    // get the next event on the queue 
    EventQueue l_queue = Toolkit.getDefaultToolkit().getSystemEventQueue(); 
    AWTEvent l_evt = l_queue.peekEvent(); 
    if (l_evt == null) { 
    // nothing left on the queue (but us), we can do it 
    SwingUtilities.invokeLater(a_runnable); 
    } else { 
    // still something in the queue, try again 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
     invokeWhenIdle(a_max_retry - 1, a_runnable); 
     } 
    }); 
    } 
} 
+0

那么有没有真正的方法知道什么时候应该运行搜索或何时应该等待,因为用户可能会点击一个单选按钮。您需要在用户上次击键后的一段时间内使用计时器来运行搜索,或者不要执行此操作,并让用户通过单击“搜索”按钮开始搜索。你不需要像这样玩'EventQueue' - 看看[如何使用Swing定时器](http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html)。当您检测到按键时,请重新启动计时器 –

+0

我的解决方法是使单选按钮不可聚焦(setFocusable(false)),以便它们不会在文本字段上导致丢失的焦点事件。仍然好奇,如果有另一种解决方案。 – Mitch

+0

您也不需要这样做,您可以使用连接到搜索字段上的按键的计时器。 –

回答

1

不是一个答案,而是一个解释正在发生的事情。也许它会引发一个想法...

问题是,mousePressed武装按钮模型和mouseReleased实际上更改模型的选定值。

当您执行FocusListener代码时,单选按钮模型处于未定义状态。即使通过使用invokeLater将FocusListener代码添加到EDT的末尾,代码仍然会在生成mouseReleased事件之前执行。

下面显示了如何编码侦听器来处理这个问题。它假设按钮的状态即将发生变化:

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

public class FocusSSCCE extends JPanel 
{ 
    public FocusSSCCE() 
    { 
     final JRadioButton radio = new JRadioButton("Radio"); 
     add(radio); 
     radio.setMnemonic('R'); 

     JTextField textField = new JTextField(10); 
     add(textField); 

     JButton button = new JButton("Button"); 
     add(button); 

     textField.addFocusListener(new FocusAdapter() 
     { 
      public void focusLost(FocusEvent e) 
      { 
       boolean isSelected = radio.isSelected(); 

       // Assumes selected state will change 

       if (radio.getModel().isArmed()) 
        isSelected = !isSelected; 

       System.out.println(isSelected); 
      } 
     }); 
    } 

    private static void createAndShowUI() 
    { 
     JFrame frame = new JFrame("FocusSSCCE"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(new FocusSSCCE()); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) 
    { 
     EventQueue.invokeLater(new Runnable() 
     { 
      public void run() 
      { 
       createAndShowUI(); 
      } 
     }); 
    } 
} 

但是,即使这种方法也无法保证工作。如果由于某种原因,用户在单选按钮上生成mousePressed事件,并且在松开鼠标之前将鼠标从单选按钮移开,则单选按钮的选定状态不会改变。

同样,即使您的原始实现睡眠250毫秒也不能保证工作,因为用户理论上可以按住鼠标超过250毫秒,这也会产生错误的值。

我对这个解决办法是使单选按钮可调焦的非

我想不出还有什么更好的办法。

编辑:

我只是想到了一个狂野的解决方案。

textField.addFocusListener(new FocusAdapter() 
{ 
    public void focusLost(FocusEvent e) 
    { 
     if (e.getOppositeComponent() instanceof JRadioButton) 
     { 
      final JRadioButton radio = (JRadioButton)e.getOppositeComponent(); 

      MouseListener ml = new MouseAdapter() 
      { 
       public void mouseReleased(MouseEvent e) 
       { 
        System.out.println(radio.isSelected()); 
        radio.removeMouseListener(this); 
       } 
      }; 

      radio.addMouseListener(ml); 
     } 

     else 
      System.out.println(radio.isSelected()); 
    } 
}); 

基本上,您的处理代码将不会执行,直到您单击单选按钮时释放鼠标。

+0

这是很好的信息。我从来没有听说过武装。 – Mitch

+0

@Mitch,看看我的编辑奇怪的解决方案:) – camickr

+0

感谢粗暴的想法,因为我会直接实现Timer,你的破解真的有效,但通过Timer处理整个和当前的JVM实例+1 – mKorbel

相关问题