2010-02-04 127 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); 
}