Nossa mano que humildade! GUJ is life
Achei o problema!!
if (evt.getKeyCode() == KeyEvent.VK_TAB) {
Ele não reconhece o que é “VK_TAB
”, mesmo estando na lista de parâmetros. Testei mudando e colocando o VK_DOWN
(seta para baixo) e deu certo! Na verdade so não ta dando certo com o TAB kk com o TAB ele pula direto pro botão que o usuário aperta depois de preencher todos os campos.
Mas no caso eu preciso do TAB porque é o padrão de mudança de campos.
Nossa, aí para cada campo novo vai ter que repetir esses códigos?
Eu criaria uma classe reaproveitável FocusHandler
para tratar essas características de foco e teclas dessa forma:
FocusHandler focusHandler = new FocusHandler();
focusHandler.add(jTextField1);
focusHandler.add(jTextField2);
focusHandler.add(jTextField3);
focusHandler.add(jTextField4);
focusHandler.add(jTextField5);
Classe FocusHandler
:
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.text.JTextComponent;
public class FocusHandler {
private final FocusListener focusListener = new FocusAdapter() {
@Override
public void focusGained(FocusEvent fe) {
onFocusGained((JTextComponent) fe.getSource());
}
};
private final KeyListener keyListener = new KeyAdapter() {
@Override
public void keyTyped(KeyEvent ke) {
if (ke.getKeyCode() == KeyEvent.VK_TAB) {
onTabTyped((JTextComponent) ke.getSource(), ke.isShiftDown());
}
}
};
private final List<JTextComponent> components = new ArrayList<>();
public void add(JTextComponent component) {
component.addFocusListener(focusListener);
component.addKeyListener(keyListener);
components.add(component);
onFocusGained(component);
}
public void remove(JTextComponent component) {
component.removeFocusListener(focusListener);
component.removeKeyListener(keyListener);
components.remove(component);
}
private void onFocusGained(JTextComponent source) {
for (JTextComponent component : components) {
component.setEditable(component == source);
}
source.requestFocus();
}
private void onTabTyped(JTextComponent source, boolean shiftPressed) {
int offset = shiftPressed ? components.size() - 1 : 0;
int increment = shiftPressed ? -1 : +1;
boolean editable = false;
for (int i = 0; i < components.size(); i++) {
JTextComponent component = components.get(offset);
component.setEditable(editable);
if (editable) {
component.requestFocus();
}
editable = component == source;
offset += increment;
}
}
}
Tela de exemplo (TAB pula para o próximo e SHIFT + TAB para o anterior):
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class Exemplo extends JFrame {
public static void main(String[] args) {
try {
Exemplo programa = new Exemplo();
programa.setDefaultCloseOperation(EXIT_ON_CLOSE);
programa.setVisible(true);
} catch (Throwable t) {
t.printStackTrace();
}
}
private JTextField jTextField1;
private JTextField jTextField2;
private JTextField jTextField3;
private JTextField jTextField4;
private JTextField jTextField5;
public Exemplo() {
super("Exemplo");
setSize(640, 480);
jTextField1 = createTextField();
jTextField2 = createTextField();
jTextField3 = createTextField();
jTextField4 = createTextField();
jTextField5 = createTextField();
Container container = getContentPane();
container.setLayout(new FlowLayout(FlowLayout.CENTER));
container.add(jTextField1);
container.add(jTextField2);
container.add(jTextField3);
container.add(jTextField4);
container.add(jTextField5);
// usar um gerenciador para o foco dos componentes
FocusHandler focusHandler = new FocusHandler();
focusHandler.add(jTextField1);
focusHandler.add(jTextField2);
focusHandler.add(jTextField3);
focusHandler.add(jTextField4);
focusHandler.add(jTextField5);
}
private JTextField createTextField() {
JTextField textField = new JTextField();
textField.setPreferredSize(new Dimension(100, 36));
return textField;
}
}
O cara é um gênio mesmo!
Só pra postar mesmo, eu acabei conseguindo de outra forma, a pessoa tem que escrever primeiro pra poder detectar:
private void tf1KeyReleased(java.awt.event.KeyEvent evt) {
tf1.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, Collections.EMPTY_SET);
if (evt.getKeyCode() == KeyEvent.VK_TAB) {
tf2.setEnabled(true);
tf1.setEnabled(false);
}
}
Só indo na onda do Staroski, se quiser um método reutilizável:
private void tf1KeyReleased(KeyEvent evt) { //evento de key released
proxCampo(evt, tf1, tf2); //tf1 e tf2 são dois textfields
}
public void proxCampo(KeyEvent evt, JTextField txt1, JTextField txt2) {
txt1.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, Collections.EMPTY_SET);
if (evt.getKeyCode() == KeyEvent.VK_TAB) {
txt2.setEnabled(true);
txt1.setEnabled(false);
}
}
Raramente você precisa programar algum código para controlar o foco dos seus componentes. O requestFocusInWindow() ou o grabFocus() vão ser usados somente em casos muitíssimo específicos, como quando vc quiser que ao clicar num botão, um componente qualquer receba o foco.
Para a troca de foco em si, não use esses métodos. O ideal é estudar um pouco como funcionam a TransversalFocusPolicy e o sistema de foco do java. Isso fará com que os saltos saiam corretos, que o CTRL+TAB também retorne e que você não perca tempo programando eventos. E o melhor, fica tudo multiplataforma e praticamente não envolve codificação nenhuma.
Siga esses tutoriais: https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html
Trocar foco em evento (principalmente se for um evento relacionado também a foco) é uma fórmula certa para o fracasso. Os eventos de foco são ligeiramente diferentes entre as várias plataformas. Não é à toa que o Java fornece dezenas de classes para evita-los (como os InputVerifiers, TransversalPolicy, etc).
Na minha humilde opinião, @staroski e @ViniGodoy são uns dos mestres de Java que tem no GUJ atualmente! Entendem tanto que chega a fazer raiva pq tudo parece simples para eles
Obrigado pela ajuda de todos!