2008-09-15 9 views
7

Per la maggior parte delle GUI che ho utilizzato, quando un controllo che contiene del testo ottiene il focus, vengono selezionati tutti i contenuti del controllo. Ciò significa che se inizi a digitare, sostituisci completamente i precedenti contenuti.Esiste un modo semplice per modificare il comportamento di un controllo Java/Swing quando viene attivato?

Esempio: il controllo di rotazione è inizializzato con il valore zero. Si scheda e digita "1" Il valore nel controllo è ora 1.

Con Swing, ciò non accade. Il testo nel controllo non è selezionato e la caratura appare a un'estremità o un'altra del testo esistente. Continuando nell'esempio sopra:

Con uno Swing JSpinner, quando si passa al controllo rotazioni, il carato si trova a sinistra. Si digita "1" e il valore nel controllo è ora 10.

Questo mi spinge (e i miei utenti) su un muro, e mi piacerebbe cambiarlo. Ancora più importante, mi piacerebbe cambiarlo globalmente in modo che il nuovo comportamento si applichi a JTextField, JPasswordField, JFormattedTextField, JTextArea, JComboBox, JSpinner e così via. L'unico modo in cui ho trovato di fare questo per aggiungere un FocusAdapter ad ogni controllo e sovrascrivere il metodo focusGained() per Do The Right Thing [tm].

Ci deve essere un modo più semplice e meno fragile. Per favore?

MODIFICA: Un'ulteriore 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 da solo, ma è una seccatura che vorrei evitare.

Motto: Tutti i bravi programmatori sono fondamentalmente pigri.

+0

Ho trovato una soluzione che soddisfa le mie esigenze. È pubblicato come risposta. –

risposta

1

Dopo aver letto le risposte finora ho passato il JPanel più esterni 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!

+0

+1 per il trucco 'setText (getText())'; Avevo elaborato tutto il resto per me stesso, ma non funzionava ancora! –

0

L'unico modo che conosco è creare un FocusListener e collegarlo al componente. Se si desidera che FocusListener diventi globale per tutti i componenti dell'applicazione, è possibile utilizzare l'Aspect Oriented Programming (AOP). Con AOP è possibile codificare una volta e applicare il vostro ascoltatore attenzione a tutti i componenti istanziati nella vostra applicazione senza dover copiare e incollare il component.addFocusListener (ascoltatore) codice in tutta l'applicazione ..

tuo aspetto sarebbe devi intercettare la creazione di un JComponent (o delle sottoclassi a cui vuoi aggiungere questo comportamento) e aggiungere il listener di 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 creare un incubo di manutenzione una volta che deciderai di cambiare il tuo comportamento globale come rimuovere l'ascoltatore per JSpinners.

Esistono molti framework AOP tra cui scegliere. Mi piace JBossAOP dato che è puro al 100% Java, ma potresti dare un'occhiata a AspectJ.

2

Quando ho avuto bisogno di questo in passato, ho creato sottoclassi dei componenti che volevo aggiungere anche funzionalità di "cancellazione automatica". ad 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 sostituzioni. Aggiungendoli e forzando una chiamata a addListener è l'approccio più generale che ho trovato.

Un'altra opzione è quella di vedere ContainerEvents su un contenitore di livello superiore con ContainerListeer per rilevare la presenza di nuovi widget e aggiungere un listener di messa a fuoco corrispondente in base ai widget che sono stati aggiunti.(ad esempio: se l'evento contenitore è causato dall'aggiunta di un campo di testo, quindi aggiungere un listener di messa a fuoco che sa come selezionare tutto il testo in un campo di testo e così via.) Se viene aggiunto un contenitore, è necessario aggiungere ricorsivamente il contenitoreListener anche a quel nuovo sottocontenitore.

In entrambi i casi, non sarà necessario parlare con gli ascoltatori di messa a fuoco nel proprio codice UI effettivo: sarà tutto a un livello superiore.

2

Non ho provato io stesso (dilettato solo qualche tempo fa), ma probabilmente si può ottenere la componente focalizzata corrente utilizzando: KeyboardFocusManager (c'è un metodo statico getCurrentKeyboardFocusManager()) un aggiunta di un PropertyChangeListener ad esso. Da lì, è possibile scoprire se il componente è un componente JText e selezionare tutto il testo.

+0

+1 Nella mia esperienza questa è la soluzione migliore se si dispone di molti controlli e/o si utilizza un designer di moduli visivi. –

2

È possibile scrivere una classe separata che collega un FocusListener al campo di testo desiderato. Tutto ciò che l'ascoltatore di messa a fuoco 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 alla JTextArea, JPasswordField, e tutti gli altri componenti di modifica del testo direttamente. Ciò consente inoltre alla classe di aggiungere tutto a caselle combinate modificabili e JSpinners, in cui il controllo sul componente dell'editor di testo potrebbe essere più limitato. possono essere aggiunti 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 necessario, dal momento che l'ascoltatore non contiene riferimenti esterni a qualsiasi altri casi, ma possono essere aggiunti per rendere le revisioni del codice andare più liscia. (! Grazie)