2010-02-04 35 views
7

Tôi đang sử dụng một vài JFormattedTextField trong chương trình của mình. Đối với một số lý do khi trường văn bản tăng tiêu điểm sau khi nhấp chuột vào trường văn bản, vị trí dấu nháy luôn nhảy sang trái (vị trí 0). Tôi muốn dấu mũ kết thúc tại vị trí được người dùng nhấp vào. Vì vậy, nếu tôi nhấp vào giữa hai chữ số, dấu mũ sẽ kết thúc ở giữa hai chữ số đó.Vị trí dấu nháy JFormattedTextField trên tiêu điểm

Vì vậy, tôi đã triển khai một FocusListener sẽ nhận được vị trí nhấp chuột và đặt vị trí dấu mũ ở đó.

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

    }); 

Tôi đã thử một số cách để làm việc của anh ấy. Tôi đã thử sử dụng từ khóa cuối cùng, hoạt động, nhưng chỉ cho một trường văn bản duy nhất.

Tôi đã sử dụng các phương pháp đặt/lấy bên trong trình nghe tập trung để gán đối tượng hiện tại, nhưng không chắc chắn về cách thực hiện điều này "an toàn" (ví dụ: chúng có cần được đồng bộ không?).

Có thể có điều gì đó tôi bị thiếu?

Trả lời

10

Bạn cần phải sử dụng một 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

Câu trả lời hay! Nhưng tại sao bạn cần phải làm điều đó trong invokeLater()? Chẳng phải mousePressed() được gọi từ chuỗi sự kiện chưa? – Jonas

+2

@Sanoj, Sự chậm trễ được giới thiệu bởi 'invokeLater' là cần thiết để nó hoạt động. Thông thường khi trường được nhấn, nó sẽ lấy tiêu điểm, làm cho trình định dạng định dạng lại giá trị và cập nhật văn bản trường. Một tác dụng phụ của điều đó là caret được di chuyển. Với 'invokeLater', phương thức' run() 'này không thực hiện cho đến khi xử lý sự kiện trọng tâm đã hoàn thành, vì vậy bạn biết rằng một khi bạn đặt dấu mũ ở đúng nơi nó sẽ ở đó. – finnw

+0

Cảm ơn bạn đã giải thích! – Jonas

7

Điều này thực sự xảy ra trong AbstractFormatter.install(JFormattedTextField), được gọi là khi lợi ích lĩnh vực tập trung.

Tôi không chắc chắn lý do tại sao nó được thiết kế theo cách này, nhưng bạn có thể thay đổi hành vi này (miễn là định dạng của bạn không thay đổi độ dài của chuỗi trong lĩnh vực này.)

Ví dụ (giả sử trường giá trị là một 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()); 
    } 
} 

Lưu ý rằng điều này không giống như các Integer định dạng mặc định. Trình định dạng mặc định sử dụng một số DecimalFormat phân tách các nhóm chữ số, ví dụ: "1,000,000". Điều này làm cho công việc khó khăn hơn vì nó thay đổi độ dài của chuỗi.

1

Được cải thiện về giải pháp của finnw một chút tôi nghĩ. Ví dụ:

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); 
} 
Các vấn đề liên quan