2013-03-04 21 views
6

Đây là mã của tôi:Tại sao JTextField.setText sẽ kích hoạt removeUpdate() của DocumentListener trước khi changedUpdate()?

import javax.swing.*; 
import javax.swing.event.DocumentEvent; 
import javax.swing.event.DocumentListener; 
import javax.swing.text.Document; 
import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

public class Frame extends JFrame { 

    private JTextField txt1 = new JTextField(10); 
    private JTextField txt2 = new JTextField(10); 
    private JButton btn = new JButton("Set Text"); 

    public Frame() { 
     super("Latihan"); 
     setLayout(new FlowLayout()); 
     btn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       txt1.setText("TEST"); txt2.setText("TEST2"); 
      } 
     }); 

     txt1.getDocument().addDocumentListener(new TheDocumentListener("txt1")); 
     txt2.getDocument().addDocumentListener(new TheDocumentListener("txt2")); 

     add(txt1); 
     add(txt2); 
     add(btn); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     pack(); 
     setVisible(true); 
    } 

    public static void main (String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new Frame(); 
      } 
     }); 
    } 
} 

class TheDocumentListener implements DocumentListener { 

    private String source; 

    public TheDocumentListener(String source) { 
     this.source = source; 
    } 
    @Override 
    public void insertUpdate(DocumentEvent e) { 
     System.out.println("insertUpdate from " + source); 
    } 

    @Override 
    public void removeUpdate(DocumentEvent e) { 
     System.out.println("removeUpdate from " + source); 
    } 

    @Override 
    public void changedUpdate(DocumentEvent e) { 
     System.out.println("changedUpdate from " + source); 
    } 
} 

Khi tôi bấm vào JButton cho lần đầu tiên, chỉ insertUpdate() sẽ được gọi là:

insertUpdate from txt1 
insertUpdate from txt2 

Nhưng nếu tôi nhấp vào nút một lần nữa, removeUpdate() sẽ được gọi trước insertUpdate():

removeUpdate from txt1 
insertUpdate from txt1 
removeUpdate from txt2 
insertUpdate from txt2 

Đây có phải là hành vi mong đợi hoặc có điều gì đó sai trong mã của tôi không?

Tôi có thể đặt insertUpdate phương thức duy nhất được gọi khi thực hiện JTextField.setText không? Tôi muốn đảm bảo rằng removeUpdate chỉ được gọi khi người dùng xóa văn bản trong trường văn bản. Làm thế nào để làm điều đó?

Trả lời

5

Đây là hành vi dự kiến ​​thay thế chuỗi. Điều thực sự là setText() là xóa toàn bộ chuỗi và đặt chuỗi mới. Đây là việc thực hiện JTextField.setText():

public void setText(String t) { 
    try { 
     Document doc = getDocument(); 
     if (doc instanceof AbstractDocument) { 
      ((AbstractDocument)doc).replace(0, doc.getLength(), t,null); 
     } 
     else { 
      doc.remove(0, doc.getLength()); 
      doc.insertString(0, t, null); 
     } 
    } catch (BadLocationException e) { 
    UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this); 
    } 
} 

Như bạn thấy, AbstractDocument.replace() được thực hiện cho AbstractDocument tài liệu. Nếu không, remove()insert() được thực hiện.

Từ AbstractDocument.replace() tài liệu:

Xóa vùng văn bản từ bù đắp để bù đắp + chiều dài, và thay thế nó bằng văn bản. Việc triển khai thực hiện như thế nào, một số triển khai có thể coi đây là hai hoạt động riêng biệt: loại bỏ được chèn tiếp theo, một số khác có thể xử lý thay thế thành một hoạt động nguyên tử.

Vì vậy, nó phụ thuộc vào việc triển khai tài liệu. Ví dụ: PlainDocument thừa hưởng triển khai cơ bản AbstractDocument. A PlainDocument là tài liệu mặc định cho các trường văn bản.

Bạn luôn có thể tạo riêng cho mình việc triển khai tài liệu nếu cần hoặc có thể cài đặt bộ lọc tài liệu. Xem hướng dẫn Using Text Components để biết chi tiết. Không chắc chắn, lý do đằng sau hành vi thay đổi này bạn đang cố gắng đạt được là gì.

+1

Lý do là để mô phỏng ràng buộc JTextField vì setText() không bị ràng buộc. Khi nói đến liên kết lẫn nhau, nó phải là: thay đổi sang thuộc tính ràng buộc khác sẽ được truyền tới JTextField.text; và gọi đến JTextField.text nên được truyền tới thuộc tính bị ràng buộc. Nhưng những gì thực sự xảy ra bây giờ là thay đổi để JTextField.text đôi khi sẽ cháy 1 hoặc 2 sự kiện nghe tài liệu và thật khó để quyết định khi nào để ngăn chặn các ràng buộc lẫn nhau. – jocki

Các vấn đề liên quan