Problema con il transferFocus

di il
9 risposte

Problema con il transferFocus

Buongiorno,

Nell'evento KeyReleased di un campo di testo in cui inserisco il giorno del mese, ho inserito questo codice che mi serve per far muovere il cursore al campo successivo nel momento in cui ho inserito due cifre nel campo TxtGG, ma non mi deve far passare al campo successivo se vi ritorno sopra con il Tab, e funziona.
La variabile iOldDDLen è dichiarata a livello del modulo della Form.

   if (TxtGG.getText().length() == 2 && iOldDDLen == 1) {
     iOldDDLen = 0;
     TxtGG.transferFocus();
   } else {
     iOldDDLen = TxtGG.getText().length();
   }


Siccome però questa funzionalità mi serve per vari campi in molte Form ho pensato di creare un metodo in una classe a parte (che uso in tutte le form) per ottenere lo stesso risultato, ma non funziona.

 public int CheckForFocus(javax.swing.JTextField jTxtField, int iOldLengh) {
   if (jTxtField.getText().length() == 2 && iOldLengh == 1) {
     jTxtField.transferFocus();
     return 0;
   } else {
     return jTxtField.getText().length();
   }
 }

Domanda: per caso il transferFocus funziona solo all'interno di un metodo della stessa Form?
Oppure dipende da qualche mio errore nel codice?

9 Risposte

  • Re: Problema con il transferFocus

    Direi la seconda.

    Il metodo transferFocus() è invocato sull'istanza della JTextField (ovunque questa istanza sia referenziata).

    Ciò che conta è che quel metodo venga invocato all'interno del EDT.

  • Re: Problema con il transferFocus

    05/12/2022 - SpiritoLibero ha scritto:


    Ciò che conta è che quel metodo venga invocato all'interno del EDT.

    Perdonami, come faccio a capire se il metodo è all'interno dello stesso EDT?

    Tu vedi qualche anomalia nel codice che ho riportato?
    Perché mi sembra un codice decisamente semplice.
    Non ho fatto altro che riportare il codice originale nel metodo dell'altra classe parametrizzandolo con l'argomento iOldLengh ricevuto dal metodo.

  • Re: Problema con il transferFocus

    Non ho idea di come e dove venga usato quel codice.

    L'EDT è uno ed uno solo in tutta l'applicazione: è il thread che si occupa di dispacciare gli eventi grafici di Swing. Se non stai eseguendo quel codice all'interno di qualche tuo thread custom, ma lo stai eseguendo all'interno di una callback di un evento, allora sei nel EDT.

    Io vedo una leggera differenza tra i due codici, ma non posso sapere se questo incide o meno: nel primo codice assegni il valore 0 alla variabile iOldDDLen e solo DOPO vai a spostare il focus; nel secondo codice, invece non c'è alcun assegnamento a nessuna variabile, ma immagino che il valore venga restituito dal metodo… il problema è che PRIMA sposti il focus e poi il valore viene restituito. Non so se questo incida su qualche tua logica di funzionamento.

  • Re: Problema con il transferFocus

    Innanzitutto ti ringrazio per il tuo interessamento e grazie per le indicazioni.

    Hai visto bene; anche a me è venuto il dubbio che il fatto di usare il transferFocus() prima del return potesse essere un problema, ma come potrei fare diversamente?

    In pratica se faccio così funziona:

    
     private void TxtGGKeyReleased(java.awt.event.KeyEvent evt) {                
       if (TxtGG.getText().length() == 2 && iOldDDLen == 1) {
         iOldDDLen = 0;
         TxtGG.transferFocus();
       } else {
         iOldDDLen = TxtGG.getText().length();
       }
     }                                      

    invece così non funziona, (clWin è la classe in cui ho messo il metodo CheckForFocus) ovvero non mi esegue il passaggio del fuoco al campo successivo

     private void TxtGGKeyReleased(java.awt.event.KeyEvent evt) {           
       iOldDDLen = clWin.CheckForFocus(TxtGG, iOldDDLen);
     }         
  • Re: Problema con il transferFocus

    Non ho ben chiaro come deve funzionare la tua applicazione, ma proverei a spostare quella variabile intera all'interno di un oggetto da passare al metodo. Qualcosa di questo tipo:

    public class Controllo {
       private int iOldDDLen;
       
       public int getIOldDDLen() {
          return iOldDDLen;
       }
    
       public void setIOldDDLen(int iOldDDLen) {
          this.iOldDDLen = iOldDDLen;
       }
    }

    Dove hai dichiarato la variabile iOldDDLen andrai a dichiarare ed istanziare un oggetto di tipo Controllo. Esempio:

    // private int iOldDDLen;
    private Controllo idControllo = new Controllo();

    In modo da replicare esattamente la logica iniziale (a questo punto la funzione può essere void):

    public void checkForFocus(javax.swing.JTextField jTxtField, Controllo idControllo) {
       if (jTxtField.getText().length() == 2 && idControllo.getIOldDDLen() == 1) {
         idControllo.setIOldDDLen(0);
         jTxtField.transferFocus();
       } else {
         idControllo.setIOldDDLen( jTxtField.getText().length() );
       }
    }

    Ovviamente dovrai sostituire quella variabile con l'oggetto (e relativa chiamata al metodo getter/setter) ovunque la variabile venga usata.

    L'utilizzo ora:

    private void TxtGGKeyReleased(java.awt.event.KeyEvent evt) {           
       clWin.checkForFocus(TxtGG, idControllo);
    }        
  • Re: Problema con il transferFocus

    Carissimo SpiritoLibero, mi avevi fatto venire una speranza, ma non funziona nemmeno questo.

    Ho un dubbio.
    Potrebbe dipendere dal fatto che il metodo checkForFocus l'ho messo all'interno di una classe che fa parte di una package differente da quello a cui appartiene la Form con i campi da controllare?

    In pratica la Form fa parte del package principale del progetto, mentre il package di checkForFocus fa parte di un altro progetto, in cui ho raggruppato tutti i metodi generici che uso nelle mie applicazioni, una sorta di libreria di sorgenti.

    Comunque se ti va di provare è sufficiente fare una form con due campi di testo, e nel TxtGGKeyReleased del primo usi il codice che ho riportato all'inizio che lo metti in un'altra classe.

  • Re: Problema con il transferFocus

    No, la posizione della classe in termini di package non c'entra nulla. Potrebbe anche stare in una libreria esterna al progetto.

    Io ho provato questo codice e mi sembra funzionare come richiedi (nota che il metodo l'ho inserito all'interno di una classe Checker che non ha nulla a che vedere con il resto dell'applicazione… ovviamente non ho package in ballo perchè ho scritto il tutto al volo su un notepad, ma potrei avere anche un package diverso per ciascuna classe, non cambierebbe nulla):

    import java.awt.*;
    import javax.swing.*;
    import java.awt.event.*;
    
    public class Finestra extends JFrame {
    
       private JTextField txt1;
       private JTextField txt2;
       private Controllo idC;
    
       public Finestra() {
          setTitle("Titolo");
          setSize(800, 600);
          setLocationRelativeTo( null );
          setDefaultCloseOperation( DISPOSE_ON_CLOSE );
          initComponents();
       }
    
       private void initComponents() {
          Container c = getContentPane();
          c.setLayout( new BorderLayout() );
    
          JPanel jp = new JPanel( new GridLayout(1, 2) );
    
          idC = new Controllo();
          idC.setIOldDDLen(0);
    
          txt1 = new JTextField();
          txt2 = new JTextField();
    
          txt1.addKeyListener( new KeyAdapter() {
             @Override
             public void keyReleased(KeyEvent ke) {
                Checker.checkForFocus(txt1, idC);
             }
          });
    
          jp.add( txt1 );
          jp.add( txt2 );
    
          c.add(jp, BorderLayout.NORTH);
       }
    
       public static void main(String[] args) {
          try {
             UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
          } catch (Exception e) { /* L&F */ }
          SwingUtilities.invokeLater( () -> { new Finestra().setVisible( true ); } );
       }
    }
    
    class Controllo {
       private int iOldDDLen;
       
       public int getIOldDDLen() {
          return iOldDDLen;
       }
    
       public void setIOldDDLen(int iOldDDLen) {
          this.iOldDDLen = iOldDDLen;
       }
    }
    
    
    class Checker {
       public static void checkForFocus(javax.swing.JTextField jTxtField, Controllo idControllo) {
          if (jTxtField.getText().length() == 2 && idControllo.getIOldDDLen() == 1) {
            idControllo.setIOldDDLen(0);
            jTxtField.transferFocus();
          } else {
            idControllo.setIOldDDLen( jTxtField.getText().length() );
          }
       }
    }
  • Re: Problema con il transferFocus

    Cribbio! Il tuo esempio Funziana!

    Però da quel che vedo l'hai fatto a manina e ti sei creato un Listener ad hoc.
    Invece io sto usando NetBenas come editor e sfrutto gli eventi che mi associa lui ai campi Text.

    Non vorrei che ci fosse di mezzo lo zampino di NetBenas.

    Adesso faccio un po' di prove per capire meglio la situazione e scoprire l'arcano.

    Poi ti aggiorno.

  • Re: Problema con il transferFocus

    Caro SpiritoLibero per me sei un mito!

    Dopo varie prove per creare un progettino nuovo in NetBeas che riproducesse il tuo esempio sono riuscito a farlo funzionare!
    Non ci sarei mai arrivato alla soluzione di creare una classe apposta (la Controllo) per gestire il contatore di caratteri.
    Che tra l'altro mi evita la dichiarazione di una varibile per ogni campo della form che devo controllare.

    Quindi ho "aggiustato" il mio primo tentativo all'interno del mio programma e funziona alla grande!
    E credo di intuire perché con la mia soluzione iniziale non funzionasse.

    Ho anche aggiunto un argomento alla checkForFocus per il numero massimo di caratteri così lo posso usare per campi di lunghezze differenti, come un campo per l'anno che è di 4 caratteri.

    Non so come ringraziarti! Va bene una pizza?

Devi accedere o registrarti per scrivere nel forum
9 risposte