2010-02-04 6 views
7

J'utilise quelques objets JFormattedTextField dans mon programme. Pour une raison ou une autre, lorsque le champ de texte devient actif après un clic sur le champ de texte, la position du curseur saute toujours vers la gauche (position 0). Je voudrais que le curseur se termine à l'endroit cliqué par l'utilisateur. Donc, si je clique entre deux chiffres, le signe d'insertion devrait se retrouver entre ces deux chiffres.Position du curseur JFormattedTextField au focus

J'ai donc implémenté un FocusListener qui obtiendrait l'emplacement du clic et définirait la position du curseur.

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) {} 

    }); 

J'ai essayé un certain nombre de choses pour que son travail fonctionne. J'ai essayé d'utiliser le mot-clé final, qui fonctionne, mais seulement pour un seul champ de texte. J'ai utilisé les méthodes set/get à l'intérieur de l'écouteur de focus pour assigner l'objet actuel, mais je ne suis pas sûr de la façon de le rendre "sûr" (par exemple, ont-ils besoin d'être synchronisés?).

Peut-être qu'il manque quelque chose?

Répondre

10

Vous devez utiliser un 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

Bonne réponse! Mais pourquoi avez-vous besoin de le faire dans invokeLater()? MousePressed() n'est-il pas invoqué à partir du Event-thread de toute façon? – Jonas

+2

@Sanoj, Le délai introduit par 'invokeLater' est nécessaire pour que cela fonctionne. Normalement, lorsque le champ est cliqué, il obtient le focus, ce qui oblige le formateur à reformater la valeur et à mettre à jour le texte du champ. Un effet secondaire de cela est que le curseur est déplacé. Avec 'invokeLater', cette méthode' run() 'ne s'exécute pas tant que la gestion des événements de focus n'est pas terminée, donc vous savez qu'une fois que vous avez placé le curseur au bon endroit, il restera sur place. – finnw

+0

Merci pour l'explication! – Jonas

7

Cela se fait dans AbstractFormatter.install(JFormattedTextField), qui est appelée lorsque les gains se concentrent sur le terrain.

Je ne sais pas pourquoi il est conçu de cette façon, mais vous pouvez modifier ce comportement (à condition que votre formatter ne change pas la longueur de la chaîne dans le champ.)

Exemple (en supposant que le champ valeur est un 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()); 
    } 
} 

Notez que ce n'est pas la même chose que le formateur par défaut Integer. Le formateur par défaut utilise un DecimalFormat qui sépare les groupes de chiffres, par ex. "1,000,000". Cela rend la tâche plus difficile car elle modifie la longueur de la chaîne.

1

Amélioré sur la solution de finnw un peu je pense. Exemple:

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); 
} 
Questions connexes