7

私が使用したほとんどの GUI では、テキストを含むコントロールがフォーカスされると、コントロールの内容全体が選択されます。つまり、入力を開始しただけで、以前の内容が完全に置き換えられます。

例: 値ゼロで初期化されたスピン コントロールがあります。タブで移動して「1」と入力すると、コントロールの値が 1 になります。

Swing では、これは起こりません。コントロール内のテキストは選択されておらず、既存のテキストの端または端にカラットが表示されます。上記の例の続き:

Swing JSpinner では、タブでスピン コントロールに移動すると、カラットは左側にあります。「1」と入力すると、コントロールの値が 10 になります。

これは私 (および私のユーザー) を壁に突き動かします。私はそれを変えたいと思っています。さらに重要なのは、新しい動作が JTextField、JPasswordField、JFormattedTextField、JTextArea、JComboBox、JSpinner などに適用されるように、グローバルに変更したいということです。これを行う唯一の方法は、各コントロールに FocusAdapter を追加し、focusGained() メソッドをオーバーライドして Do The Right Thing[tm] にすることです。

もっと簡単で壊れにくい方法があるはずです。お願いします?

編集: この特定のケースに関する 1 つの追加情報。私が使用しているフォームは、Idea のフォーム デザイナーを使用して生成されました。つまり、通常、コンポーネントを作成するためのコードを実際に書くことはありません。自分で作成したいということを Idea に伝えることは可能ですが、それは避けたい面倒です。

モットー: 優れたプログラマーは皆、基本的に怠け者です。

4

5 に答える 5

2

過去にこれが必要になったとき、「自動クリア」機能も追加したいコンポーネントのサブクラスを作成しました。例えば:

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 の呼び出しを強制することは、私が見つけた最も一般的なアプローチです。

もう 1 つのオプションは、ContainerListeer を使用して最上位のコンテナーで ContainerEvents を監視し、新しいウィジェットの存在を検出し、追加されたウィジェットに基づいて対応するフォーカス リスナーを追加することです。(例: コンテナー イベントが TextField の追加によって発生する場合は、TextField 内のすべてのテキストを選択する方法を認識しているフォーカス リスナーを追加するなど)。コンテナーが追加された場合は、ContainerListener を再帰的に追加する必要があります。その新しいサブコンテナにも。

いずれにせよ、実際の UI コードでフォーカス リスナーをいじる必要はありません。すべて上位レベルで処理されます。

于 2008-09-15T20:32:04.607 に答える
2

私はこれを自分で試したことはありませんが (少し前に手を出しただけです)、次を使用して現在フォーカスされているコンポーネントを取得できる可能性があります。そこから、コンポーネントが JTextComponent であるかどうかを確認し、すべてのテキストを選択できます。

于 2008-09-15T21:53:12.743 に答える
2

目的のテキスト フィールドに 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、およびその他すべてのテキスト編集コンポーネントに直接追加できます。これにより、クラスは編集可能なコンボ ボックスと JSpinners にすべて選択を追加できるようになり、テキスト エディター コンポーネントに対する制御がより制限される場合があります。便利なメソッドを追加できます:

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

また、リスナーには他のインスタンスへの外部参照が含まれていないため、remove リスナー メソッドは必要ない可能性がありますが、コード レビューをよりスムーズにするために追加することができます。

于 2008-09-16T18:09:17.437 に答える
1

これまでの返信を読んだ後(ありがとう!)、最も外側の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);
            }
        }
    }
}

できます!

于 2008-09-17T18:30:40.780 に答える
0

私が知っている唯一の方法は、FocusListener を作成してコンポーネントにアタッチすることです。この FocusListener をアプリケーション内のすべてのコンポーネントに対してグローバルにしたい場合は、アスペクト指向プログラミング (AOP) の使用を検討してください。AOP を使用すると、アプリケーション全体でcomponent.addFocusListener(listener)コードをコピー アンド ペーストすることなく、一度コーディングして、アプリでインスタンス化されたすべてのコンポーネントにフォーカス リスナーを適用できます。

アスペクトは、JComponent (またはこの動作を追加するサブクラス) の作成をインターセプトし、新しく作成されたインスタンスにフォーカス リスナーを追加する必要があります。AOP アプローチは、FocusListener をコード全体にコピー アンド ペーストするよりも優れています。これは、すべてを 1 つのコードに保持し、リスナーを削除するなどのグローバルな動作を変更することを決定した後、メンテナンスの悪夢を作成しないためです。 Jスピナーズ。

選択できる AOP フレームワークは数多くあります。JBossAOPは 100% 純粋な Java であるため気に入っていますが、AspectJもご覧になることをお勧めします。

于 2008-09-15T20:23:27.123 に答える