포커스가 있을 때 Java/Swing 컨트롤의 동작을 변경하는 쉬운 방법이 있습니까?

StackOverflow https://stackoverflow.com/questions/66455

  •  09-06-2019
  •  | 
  •  

문제

내가 사용한 대부분의 GUI에서는 텍스트가 포함된 컨트롤에 초점이 맞춰지면 컨트롤의 전체 내용이 선택됩니다.즉, 방금 입력을 시작하면 이전 내용이 완전히 교체됩니다.

예:값 0으로 초기화된 스핀 컨트롤이 있습니다.탭하고 "1"을 입력하면 이제 컨트롤의 값이 1이 됩니다.

Swing을 사용하면 이런 일이 발생하지 않습니다.컨트롤의 텍스트는 선택되지 않으며 캐럿은 기존 텍스트의 한쪽 끝에 나타납니다.위의 예를 계속하면 다음과 같습니다.

Swing JSpinner를 사용하여 스핀 컨트롤을 탭하면 캐럿이 왼쪽에 있습니다."1"을 입력하면 컨트롤의 값이 이제 10이 됩니다.

이로 인해 저와 사용자들은 벽에 부딪히게 되었고 저는 이를 바꾸고 싶습니다.더 중요한 점은 JTextField, JPasswordField, JFormattedTextField, JTextArea, JComboBox, JSpinner 등에 새 동작이 적용되도록 전역적으로 변경하고 싶다는 것입니다.각 컨트롤에 FocusAdapter를 추가하고 올바른 일을 수행하기 위해 focusGained() 메서드를 재정의하는 것이 제가 찾은 유일한 방법입니다.

더 쉽고 덜 깨지기 쉬운 방법이 있을 겁니다.제발?

편집하다:이 특정 사례에 대한 추가 정보입니다.제가 작업 중인 양식은 Idea의 양식 디자이너를 사용하여 생성되었습니다.이는 일반적으로 실제로 구성 요소를 생성하는 코드를 작성하지 않는다는 의미입니다.Idea에 직접 만들고 싶다고 말할 수도 있지만 저는 그런 번거로움을 피하고 싶습니다.

금언:모든 좋은 프로그래머는 기본적으로 게으르다.

도움이 되었습니까?

해결책 4

지금까지 답변을 읽은 후(감사합니다!) 가장 바깥쪽 JPanel을 다음 메서드에 전달했습니다.

void addTextFocusSelect(JComponent component){
    if(component instanceof JTextComponent){
        component.addFocusListener(new FocusAdapter() {
                @Override
                public void focusGained(FocusEvent event) {
                    super.focusGained(event);
                    JTextComponent component = (JTextComponent)event.getComponent();
                    // a trick I found on JavaRanch.com
                    // Without this, some components don't honor selectAll
                    component.setText(component.getText());
                    component.selectAll();
                }
            });

    }
    else
    {
        for(Component child: component.getComponents()){
            if(child instanceof JComponent){
                addTextFocusSelect((JComponent) child);
            }
        }
    }
}

효과가있다!

다른 팁

과거에 이 기능이 필요했을 때 "자동 지우기" 기능도 추가하고 싶은 구성 요소의 하위 클래스를 만들었습니다.예:

public class AutoClearingTextField extends JTextField {
   final FocusListener AUTO_CLEARING_LISTENER = new FocusListener(){
      @Override
      public void focusLost(FocusEvent e) {
         //onFocusLost(e);
      }

      @Override
      public void focusGained(FocusEvent e) {
         selectAll();
      }
   };

   public AutoClearingTextField(String string) {
      super(string);
      addListener();
   }

   private void addListener() {
      addFocusListener(AUTO_CLEARING_LISTENER);      
   }
}

가장 큰 문제는 재정의를 작성하지 않고 모든 표준 생성자를 얻을 수 있는 "좋은" 방법을 찾지 못했다는 것입니다.이를 추가하고 addListener를 강제로 호출하는 것이 내가 찾은 가장 일반적인 접근 방식입니다.

또 다른 옵션은 ContainerListeer를 사용하여 최상위 컨테이너에서 ContainerEvents를 감시하여 새 위젯의 존재를 감지하고 추가된 위젯을 기반으로 해당 포커스 리스너를 추가하는 것입니다.(예:TextField를 추가하여 컨테이너 이벤트가 발생한 경우 TextField의 모든 텍스트를 선택하는 방법을 알고 있는 포커스 리스너를 추가하는 등의 작업을 수행합니다.) 컨테이너가 추가되면 해당 새 컨테이너에 ContainerListener를 재귀적으로 추가해야 합니다. 하위 컨테이너도 마찬가지입니다.

어느 쪽이든 실제 UI 코드에서 포커스 리스너에 대해 고민할 필요가 없습니다. 모두 더 높은 수준에서 처리됩니다.

나는 이것을 직접 시도하지 않았지만(오직 전에만 시도해 보았지만) 다음을 사용하여 현재 초점을 맞춘 구성 요소를 얻을 수 있습니다.KeyboardFocusManager (GetCurrentKeyboardFocusManager ()가 정적 메소드가 있습니다.여기에서 구성 요소가 JTextComponent인지 확인하고 모든 텍스트를 선택할 수 있습니다.

원하는 텍스트 필드에 FocusListener를 연결하는 별도의 클래스를 작성할 수 있습니다.포커스 리스너가 하는 일은 포커스를 얻을 때 텍스트 위젯에서 selectAll()을 호출하는 것뿐입니다.

public class SelectAllListener implements FocusListener {
  private static INSTANCE = new SelectAllListener();

  public void focusLost(FocusEvent e) { }

  public void focusGained(FocusEvent e) {
    if (e.getSource() instanceof JTextComponent) {  
      ((JTextComponent)e.getSource()).selectAll();
    }
  };

  public static void addSelectAllListener(JTextComponent tc) {
    tc.addFocusListener(INSTANCE);
  }

  public static void removeSelectAllListener(JTextComponent tc) {
    tc.removeFocusListener(INSTANCE);
  }
}

JTextComponent를 인수로 허용하면 이 동작을 JTextArea, JPasswordField 및 기타 모든 텍스트 편집 구성 요소에 직접 추가할 수 있습니다.또한 이를 통해 클래스는 편집 가능한 콤보 상자 및 JSpinner에 모두 선택을 추가할 수 있으며, 여기서 텍스트 편집기 구성 요소에 대한 제어가 더 제한될 수 있습니다.편의 메서드를 추가할 수 있습니다.

public static void addSelectAllListener(JSpinner spin) {
  if (spin.getEditor() instanceof JTextComponent) {
    addSelectAllListener((JTextComponent)spin.getEditor());
  }
}

public static void addSelectAllListener(JComboBox combo) {
  JComponent editor = combo.getEditor().getEditorComponent();
  if (editor instanceof JTextComponent) {
    addSelectAllListener((JTextComponent)editor);
  }
}

또한 제거 리스너 메서드는 리스너에 다른 인스턴스에 대한 외부 참조가 포함되어 있지 않기 때문에 필요하지 않을 수 있지만 코드 검토를 더 원활하게 하기 위해 추가할 수 있습니다.

내가 아는 유일한 방법은 FocusListener를 생성하여 구성 요소에 연결하는 것입니다.이 FocusListener가 애플리케이션의 모든 구성 요소에 전역적으로 적용되도록 하려면 AOP(Aspect Oriented 프로그래밍) 사용을 고려할 수 있습니다.AOP를 사용하면 코드를 한 번만 작성하고 복사하여 붙여넣을 필요 없이 앱에서 인스턴스화된 모든 구성 요소에 포커스 리스너를 적용할 수 있습니다. 컴포넌트.addFocusListener(리스너) 애플리케이션 전반의 코드..

당신의 관점은 JComponent(또는 이 동작을 추가하려는 하위 클래스)의 생성을 가로채고 새로 생성된 인스턴스에 포커스 리스너를 추가해야 합니다.AOP 접근 방식은 FocusListener를 전체 코드에 복사하여 붙여넣는 것보다 낫습니다. 왜냐하면 모든 코드를 단일 코드에 유지하고 리스너 제거와 같은 전역 동작을 변경하기로 결정한 후에도 유지 관리의 악몽을 만들지 않기 때문입니다. JSpinners.

선택할 수 있는 AOP 프레임워크가 많이 있습니다.좋아요 JBossAOP 100% 순수 Java이므로 다음을 살펴보고 싶을 수도 있습니다. 측면J.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top