2010-02-04 91 views
7

我在程序中使用了几个JFormattedTextField。出于某种原因,当文本字段点击文本字段后,文本字段获得焦点时,插入符总是跳到左侧(位置0)。我希望插入符号最终位于用户点击的位置。所以如果我在两位数之间点击,那么插入符应该在两位数之间结束。JFormattedTextField插入焦点位置

所以我实现了一个FocusListener,它将得到点击位置并在那里设置插入符的位置。

FocusListener focusListener = new FocusListener(){ 


    public void focusGained(FocusEvent evt) { 

     JFormettedTextField jftf = (JFormattedTextField) evt.getSource(); 

     //This is where the caret needs to be. 
     int dot = jftf.getCaret().getDot(); 

     SwingUtilities.invokeLater(new Runnable() { 

     public void run() { 
'the textField that has focus'.setCaretPosition('Some how get the evt or dot');    
       } 
      }); 
     } 

    public void focusLost (FocusEvent evt) {} 

    }); 

我试过很多东西让他上班。我尝试过使用final关键字,它可以工作,但只适用于单个文本框。我已经在焦点侦听器中使用set/get方法来分配当前对象,但我不知道如何使这个“安全”(例如他们需要同步吗?)。

也许有一些我失踪?

回答

10

您需要使用的MouseListener:

MouseListener ml = new MouseAdapter() 
{ 
    public void mousePressed(final MouseEvent e) 
    { 
     SwingUtilities.invokeLater(new Runnable() 
     { 
      public void run() 
      { 
       JTextField tf = (JTextField)e.getSource(); 
       int offset = tf.viewToModel(e.getPoint()); 
       tf.setCaretPosition(offset); 
      } 
     }); 
    } 
}; 

formattedTextField.addMouseListener(ml); 
+0

很好的答案!但为什么你需要在invokeLater()中做到这一点?无论如何,是不是从event-thread调用mousePressed()? – Jonas 2010-02-04 20:42:17

+2

@Sanoj,'invokeLater'引入的延迟对于它的工作是必要的。通常当单击该字段时,它会获得焦点,这会导致格式化程序重新格式化该值并更新字段文本。这样做的副作用是脱字符被移动。使用'invokeLater',这个'run()'方法在焦点事件处理完成之前不会执行,所以你知道一旦你把插入符号放在正确的地方,它就会停留在那里。 – finnw 2010-02-04 21:10:37

+0

感谢您的解释! – Jonas 2010-02-04 23:01:50

7

实际上,这发生在AbstractFormatter.install(JFormattedTextField),被称为当字段获得焦点。

我不知道为什么它是这样设计的,但是你可以重写此行为(只要你的格式不改变在该领域的字符串的长度)。

实例(假设场值是int):

class IntFormatter extends AbstractFormatter { 
    @Override 
    public void install(final JFormattedTextField ftf) { 
     int prevLen = ftf.getDocument().getLength(); 
     int savedCaretPos = ftf.getCaretPosition(); 
     super.install(ftf); 
     if (ftf.getDocument().getLength() == prevLen) { 
      ftf.setCaretPosition(savedCaretPos); 
     } 
    } 

    public Object stringToValue(String text) throws ParseException { 
     return Integer.parseInt(text); 
    } 

    public String valueToString(Object value) throws ParseException { 
     return Integer.toString(((Number) value).intValue()); 
    } 
} 

注意,这是不一样的默认Integer格式化。默认格式化程序使用DecimalFormat来分隔数字组,例如, "1,000,000"。这使得任务变得更难,因为它改变了字符串的长度。

1

有点改进了finnw的解决方案。例如:

public static void main(String[] args) { 
    NumberFormat format = NumberFormat.getInstance(); 
    NumberFormatter formatter = new NumberFormatter(format) { 
     @Override 
     public void install(JFormattedTextField pField) { 
      final JFormattedTextField oldField = getFormattedTextField(); 
      final int oldLength = pField.getDocument().getLength(); 
      final int oldPosition = pField.getCaretPosition(); 

      super.install(pField); 

      if (oldField == pField && oldLength == pField.getDocument().getLength()) { 
       pField.setCaretPosition(oldPosition); 
      } 
     } 
    }; 
    JFormattedTextField field = new JFormattedTextField(formatter); 
    field.setValue(1234567890); 

    JOptionPane.showMessageDialog(null, field); 
}