2016-08-29 11 views
0

두 개의 텍스트 필드 (지금부터 A와 B)가 사용자 입력과 동일한 내용을 공유하고 싶습니다. 하나의 거울을 다른 거울 (B 거울 A) 또는 반대편 (A 거울 B)으로 만들 수 있습니다. 그러나 두 DocumentListeners를 모두 유지하면 예외가 throw되기 시작합니다.JTextFields 및 DocumentListeners

오라클의 Docs에 따르면 DocumentListener를 사용하여 Listener 자체에서 문서의 내용을 변경할 수 없습니다. 나는 이미 첫 번째 경우 (B 미러 A) 또는 그 반대의 경우에 그것을 수행 한 이후로 이상한 것을 발견합니다. 어쨌든 코드는 여전히 "작동"하지만 트리거 된 두 개의 이벤트가 발생할 때마다 예외가 발생합니다.

KeyListeners는이 특정 케이스에 대해 신뢰할 수 없으며 DocumentListener가 제공하는 실시간 모양이 좋기 때문에 버튼 사용을 거부합니다.

제안 사항?

여기 내 코드입니다 :

import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JTextField; 
import javax.swing.event.DocumentEvent; 
import javax.swing.event.DocumentListener; 

public class Mirror { 
    private JTextField oriText; 
    private JTextField mirrorText; 
    private static int debugCounter; //Counts the times an Event is Triggered. 

    public static void main(String[] args) { 
     Mirror gui = new Mirror(); 
     gui.build(); 
    } 

    public void build(){ 

     JFrame frame = new JFrame(); 
     JPanel panel = new JPanel(); 
     panel.setLayout(new GridBagLayout()); 
     GridBagConstraints c = new GridBagConstraints(); 
     frame.getContentPane().add(panel); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     c.gridx = 0; 
     c.gridy = 0; 
     JLabel original = new JLabel("Original"); 
     panel.add(original, c); 

     c.gridy = 1; 
     oriText = new JTextField(10); 
     panel.add(oriText,c); 


     c.gridy = 2; 
     JLabel mirror = new JLabel("Mirror"); 
     panel.add(mirror, c); 

     c.gridy = 3; 
     mirrorText = new JTextField(10); 
     panel.add(mirrorText, c);   
     mirrorText.getDocument().addDocumentListener(new MyDocumentListenerII()); // Comment this line to see only the 1st Case (B mirrors A) 
     oriText.getDocument().addDocumentListener(new MyDocumentListener()); // Comment this line to see only the 2nd Case (A mirrors B) 


     frame.pack(); 
     frame.setVisible(true); 
    } 

    class MyDocumentListener implements DocumentListener{ 

     @Override 
     public void changedUpdate(DocumentEvent e) { 
      //Does nothing. 

     } 

     @Override 
     public void insertUpdate(DocumentEvent e) { 
      mirror(); 
     } 

     @Override 
     public void removeUpdate(DocumentEvent e) { 
      mirror(); 
     } 


    } 

    class MyDocumentListenerII implements DocumentListener{ 

     @Override 
     public void changedUpdate(DocumentEvent e) { 
      // Does nothing. 
     } 

     @Override 
     public void insertUpdate(DocumentEvent e) { 
      mirror1(); 
     } 

     @Override 
     public void removeUpdate(DocumentEvent e) { 
      mirror1(); 
     } 

    } 

    public void mirror(){ 
     if (!oriText.getText().equals(mirrorText.getText())){ //Without this each Event trigger the other in some sort of Paradoxical cycle. 
      mirrorText.setText(oriText.getText()); 
      debugCounter++; 
      System.out.println(debugCounter+" events triggered"); 
     } 
    } 

    public void mirror1(){ 
     if (!mirrorText.getText().equals(oriText.getText())){ 
      oriText.setText(mirrorText.getText()); 
      debugCounter++; 
      System.out.println(debugCounter+" events triggered"); 
     } 
    } 


} 

답변

0

문제는 JTextField이 모두 동기화되어야하므로 각 필드의 DocumentListener은 다른 필드를 업데이트해야합니다. 그러나이 업데이트로 인해 DocumentListener은 첫 번째 필드를 업데이트하려고 시도하고 IllegalStateException이 발생합니다. 무언가가 필드 수정을 시도하고있는 동안 DocumentListener이 실행 중일 때 발생합니다.

해결 방법은 DocumentListener이 해당 필드에 대해 실행될 때 setText(String)에 대한 호출을 차단하는 것입니다. 이것은 boolean 변수로 수행 할 수 있습니다. 아래 DocumentListener들 중 하나에 대한 코드는 다음과 blockAblockBboolean 인스턴스 필드 (또는 방법 가능 final 변수)이다

textFieldA.getDocument().addDocumentListener(new DocumentListener() { 
    @Override 
    public void removeUpdate (DocumentEvent e) { 
    blockA = true; 
    if (!blockB) textFieldB.setText(textFieldA.getText()); 
    blockA = false; 
    } 
    @Override 
    public void insertUpdate (DocumentEvent e) { 
    blockA = true; 
    if (!blockB) textFieldB.setText(textFieldA.getText()); 
    blockA = false; 
    } 
    @Override 
    public void changedUpdate (DocumentEvent e) { 
    blockA = true; 
    if (!blockB) textFieldB.setText(textFieldA.getText()); 
    blockA = false; 
    } 
}); 

. 이제 메서드가 textFieldADocumentListener에서 발생하면 textFieldA.setText(String)을 사용하지 않음을 나타내는 플래그가 설정됩니다. blockB을 설정하면 textFieldB.setText(String)이 차단되는 방식도 볼 수 있습니다. textFieldB에 대한 DocumentListener은 거의 같습니다.

이제 내에서 통화 중에 textFieldA이 설정되지 않습니다. 다른 필드와 동일합니다. 어쨌든 그러한 호출은 중복 될 것입니다 : 각 필드의 텍스트는 그 시점에서 동일합니다.

+0

Nailed it !!! 고마워, 젠장 ... 나는 보통의 "문서 필터 사용"대신에 이와 같은 대답을 얻기를 바랬다. 당신이 아마 알아 냈으므로 비록 합법적 인 것일 필요가 없다고하더라도 나는 테스트하고 싶습니다. –

0

나는이 그것을 할 수있는 '올바른'방법은 전혀 모르겠지만, 내가 한 모든 각 JTextField에 동일한 Document을 첨부했다.

은 여기 내 초기화에서 관련 부분 :

textFieldA = new JTextField(); 
textFieldA.setBounds(10, 11, 414, 20); 
textFieldA.setColumns(10); 

textFieldB = new JTextField(); 
textFieldB.setBounds(10, 42, 414, 20); 
textFieldB.setColumns(10); 
textFieldB.setDocument(textFieldA.getDocument()); 

는 이제 JTextField의 모두 동일한 문서를 가지고, 그래서 그들은 서로 다른 수 없습니다.