Esiste un modo semplice per modificare il comportamento di un controllo Java/Swing quando viene attivato?

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

  •  09-06-2019
  •  | 
  •  

Domanda

Per la maggior parte delle GUI che ho utilizzato, quando viene attivato un controllo che contiene testo, viene selezionato l'intero contenuto del controllo.Ciò significa che se inizi a digitare, sostituisci completamente i contenuti precedenti.

Esempio:Hai il controllo dello spin inizializzato con il valore zero.Ti avvicini e digiti "1". Il valore nel controllo ora è 1.

Con Swing questo non accade.Il testo nel controllo non è selezionato e il carato appare all'una o all'altra estremità del testo esistente.Continuando l'esempio sopra:

Con uno Swing JSpinner, quando passi al controllo rotazione, il carato è a sinistra.Digiti "1" e il valore nel controllo ora è 10.

Questo porta me (e i miei utenti) a un muro e mi piacerebbe cambiarlo.Ancora più importante, vorrei cambiarlo a livello globale in modo che il nuovo comportamento si applichi a JTextField, JPasswordField, JFormattedTextField, JTextArea, JComboBox, JSpinner e così via.L'unico modo che ho trovato per farlo è aggiungere un FocusAdapter a ciascun controllo e sovrascrivere il metodo focusGained() per Do The Right Thing[tm].

Deve esserci un modo più semplice e meno fragile.Per favore?

MODIFICARE:Un'informazione aggiuntiva per questo caso particolare.Il modulo con cui sto lavorando è stato generato utilizzando il form designer di Idea.Ciò significa che normalmente non scrivo il codice per creare i componenti.È possibile dire a Idea che vuoi crearli tu stesso, ma è una seccatura che vorrei evitare.

Motto:Tutti i bravi programmatori sono fondamentalmente pigri.

È stato utile?

Soluzione 4

Dopo aver letto le risposte finora (grazie!) ho passato il JPanel più esterno al seguente metodo:

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

Funziona!

Altri suggerimenti

Quando ne avevo bisogno in passato, ho creato sottoclassi dei componenti a cui volevo aggiungere anche la funzionalità di "cancellazione automatica".per esempio:

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

Il problema più grande è che non ho trovato un modo "buono" per ottenere tutti i costruttori standard senza scrivere override.Aggiungerli e forzare una chiamata a addListener è l'approccio più generale che ho trovato.

Un'altra opzione è controllare ContainerEvents su un contenitore di primo livello con ContainerListeer per rilevare la presenza di nuovi widget e aggiungere un ascoltatore focus corrispondente in base ai widget che sono stati aggiunti.(per esempio:se l'evento contenitore è causato dall'aggiunta di un TextField, aggiungi un ascoltatore focus che sappia come selezionare tutto il testo in un TextField e così via.) Se viene aggiunto un contenitore, devi aggiungere ricorsivamente ContainerListener a quel nuovo anche il sottocontenitore.

In ogni caso, non avrai bisogno di perdere tempo con gli ascoltatori focalizzati nel tuo vero codice dell'interfaccia utente: tutto sarà curato a un livello superiore.

Non l'ho provato personalmente (mi sono solo dilettato qualche tempo fa), ma probabilmente puoi ottenere il componente attualmente focalizzato utilizzando:KeyboardFocusManager (esiste un metodo statico getCurrentKeyBoardFocusManager ()) Un'aggiunta di un Changelistener di proprietà.Da lì puoi scoprire se il componente è un JTextComponent e selezionare tutto il testo.

È possibile scrivere una classe separata che alleghi un FocusListener al campo di testo desiderato.Tutto ciò che l'ascoltatore del focus farebbe è chiamare selectAll() sul widget di testo quando ottiene il focus.

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

Accettando un JTextComponent come argomento questo comportamento può essere aggiunto direttamente a JTextArea, JPasswordField e a tutti gli altri componenti di modifica del testo.Ciò consente inoltre alla classe di aggiungere seleziona tutto alle caselle combinate modificabili e ai JSpinner, dove il controllo sul componente editor di testo potrebbe essere più limitato.È possibile aggiungere metodi di convenienza:

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

Inoltre, i metodi di rimozione del listener sono probabilmente non necessari, poiché il listener non contiene riferimenti esterni ad altre istanze, ma possono essere aggiunti per rendere più fluide le revisioni del codice.

L'unico modo che conosco è creare un FocusListener e collegarlo al tuo componente.Se desideri che FocusListener sia globale per tutti i componenti della tua applicazione, potresti prendere in considerazione l'utilizzo della programmazione orientata agli aspetti (AOP).Con AOP è possibile codificarlo una volta e applicare il tuo focus listener a tutti i componenti istanziati nella tua app senza dover copiare e incollare il file componente.addFocusListener(ascoltatore) codice in tutta l'applicazione..

Il tuo aspetto dovrebbe intercettare la creazione di un JComponent (o delle sottoclassi a cui desideri aggiungere questo comportamento) e aggiungere il listener focus all'istanza appena creata.L'approccio AOP è migliore del copia e incolla di FocusListener sull'intero codice perché mantieni tutto in un unico pezzo di codice e non crei un incubo di manutenzione una volta che decidi di modificare il tuo comportamento globale come rimuovere il listener per JSpinner.

Esistono molti framework AOP tra cui scegliere.mi piace JBossAOP dato che è Java puro al 100%, ma ti potrebbe piacere dare un'occhiata AspettoJ.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top