[JSpinner] "Ouvindo" eventos de teclado

6 respostas
R

Olá:

Estou fazendo um teste com JSpinner. Quando clico em “Seta para Cima” ou em “Seta para Baixo” o valor do JSpinner é incrementado ou decrementado em uma unidade. Meu objetivo final é “acelerar” a variação do valor: Quando clicar CTRL + “Seta para Cima” ou CTRL + “Seta para Baixo” o valor deve ser incrementado ou decrementado em 10 unidades, por exemplo. Entretanto as coisas não estão saido como esperado. Se eu Adicionar um KeyListener para o JSpinner nada acontece. Tentei ainda usar este exemplo e este outro no Example Depot (outrora Java Alamanac), usando KeyStroke mas de novo não aconteceu nada. Abaixo, segue-se o código de teste que fiz (feito no NetBeans 6.8 ):

package testeswing;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.Arrays;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.KeyStroke;

/**
 *
 * @author rafael
 */
public class TestaSpinner extends javax.swing.JFrame {

    public static final String CTRL_UP = "CTRL_UP";
    public static final String CTRL_DOWN = "CTRL_DOWN";

    private Action action = new AbstractAction() {

        public void actionPerformed(ActionEvent e) {
            System.out.println(e);
        }
    };

    /** Creates new form TestaSpinner */
    public TestaSpinner() {
        initComponents();
        System.out.println(this.spnValor.getInputMap());
        System.out.println(Arrays.toString(this.spnValor.getRegisteredKeyStrokes()));
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        lblValor = new javax.swing.JLabel();
        spnValor = new javax.swing.JSpinner();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Teste de JSpinner");
        getContentPane().setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER, 20, 5));

        lblValor.setFont(new java.awt.Font("Tahoma", 0, 48));
        lblValor.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        lblValor.setMaximumSize(new java.awt.Dimension(100, 58));
        lblValor.setMinimumSize(new java.awt.Dimension(100, 58));
        lblValor.setPreferredSize(new java.awt.Dimension(100, 58));
        getContentPane().add(lblValor);

        spnValor.setFont(new java.awt.Font("Tahoma", 0, 48)); // NOI18N
        spnValor.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(0), null, Integer.valueOf(50), Integer.valueOf(1)));
        spnValor.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                spnValorStateChanged(evt);
            }
        });
		// Adicionando KeyListeners
        spnValor.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                spnValorKeyPressed(evt);
            }
            public void keyReleased(java.awt.event.KeyEvent evt) {
                spnValorKeyReleased(evt);
            }
            public void keyTyped(java.awt.event.KeyEvent evt) {
                spnValorKeyTyped(evt);
            }
        });
        
		// Adicionando KeyStrokes
        getContentPane().add(spnValor);
        InputMap inputMap = new InputMap();
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.CTRL_DOWN_MASK), CTRL_UP);
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_KP_UP, KeyEvent.CTRL_DOWN_MASK), CTRL_UP);
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.CTRL_DOWN_MASK), CTRL_DOWN);
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_KP_DOWN, KeyEvent.CTRL_DOWN_MASK), CTRL_DOWN);
        inputMap.setParent(this.spnValor.getInputMap(JComponent.WHEN_FOCUSED));
        spnValor.setInputMap(JComponent.WHEN_FOCUSED, inputMap);

        spnValor.getActionMap().put(CTRL_DOWN, this.action);
        spnValor.getActionMap().put(CTRL_UP, this.action);

        pack();
    }// </editor-fold>

    private void spnValorStateChanged(javax.swing.event.ChangeEvent evt) {                                      
        this.lblValor.setText(this.spnValor.getValue().toString());
    }                                     

    private void spnValorKeyPressed(java.awt.event.KeyEvent evt) {
        System.out.println("KeyPressed: " + evt);
    }

    private void spnValorKeyReleased(java.awt.event.KeyEvent evt) {
        System.out.println("KeyReleased: " + evt);
    }

    private void spnValorKeyTyped(java.awt.event.KeyEvent evt) {
        System.out.println("KeyTyped: " + evt);
    }

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new TestaSpinner().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify
    private javax.swing.JLabel lblValor;
    private javax.swing.JSpinner spnValor;
    // End of variables declaration

}

No construtor do JFrame mando imprimir os KeyStrokey registrados. O que aparece é

Bem, alguém tem idéia do que está faltando para que o JSpinner consiga ouvir “meus” eventos?

Grato,

Rafael U. C. Afonso

6 Respostas

D

Que bagunça o NetBeans faz no código, eu nunca tinha visto hehehe.

Bom, vou dar uma idéia, acho que pode funcionar.

Crie 2 SpinnerModel do tipo SpinnerNumberModel, um com incremento de 1 e outro com 10, assim:

SpinnerModel spnModel1 = new SpinnerNumberModel(0,null,50,1);
SpinnerModel spnModel10 = new SpinnerNumberModel(0,null,50,10);

Quando o CTRL for pressionado (keyPressed) você seta o model para spnModel10:
spnValor.setModel(spnModel10);

Quando o CTRL for solto (keyReleased) você seta o model para spnModel1;
spnValor.setModel(spnModel1);

Não testei, só pensei na solução… espero que ajude!

R

De fato gostava mais da forma que o Visual Editor do Eclipse organizava o código. Principalmente ele não tem essas frescuras de regiões de edição proibida. Infelizmente ele não é tão sofisticado quanto o Matisse do NB e no momento está com o desenvolvimento estagnado.

Aí que está todo o problema: Não consigo fazer com que o Spinner “ouça” o teclado. O comportamento padrão do componente é que quando você teclar seta p/cima ou seta p/baixo, o spinner incremente ou decremente em uma unidade. Tentei fuçar no código original do JSpinner mas não consegui descobrir onde é injetado este comportamento.
Quanto a criar dois modelos diferentes, não é necessário. Criei um MouseWheelListtener que quando você usa a roda do mouse o valor do Spinner é incrementado ou decrementado. Mas se junto com a roda você mantém clicado o botão direito do mouse, você pode variar o valor em dez unidade ou mais (você pode configurar o valor desse passo estendido).

Obrigado de qualquer forma.

D

Entendi o seu problema agora Rafael, fiz uns testes e também não consegui fazer o keylistener funcionar…
O JSpinner é meio estranho, eu também to apanhando pra usar ele, quero desabilitar o editor dele, permitindo que o valor seja alterado apenas pelas setas. Se eu usar setEnable(false) ele desabilita as setas também, tentei desabilitar só o editor mas também não fez nada… Parece tão simples de usar :?

A

ei nao falem mau do meu Netbeans ein, amo ele de montao kkkkk :lol:

moleza cara, coloca isso depois de

initComponents();

do codigo do Netbeans

((javax.swing.JSpinner.DefaultEditor) TeuObjetojSpinner.getEditor()).getTextField().addKeyListener(
                new java.awt.event.KeyListener() {

                    public void keyTyped(java.awt.event.KeyEvent e) {
                        //Exemplo
                        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                            JOptionPane.showMessageDialog(null, "Pressionou ENTER");
                        }
                    }

                    public void keyPressed(java.awt.event.KeyEvent e) {
                    }

                    public void keyReleased(java.awt.event.KeyEvent e) {
                    }
                });

vlwwwwwwwwww

R

ambuzr:
ei nao falem mau do meu Netbeans ein, amo ele de montao kkkkk :lol:

moleza cara, coloca isso depois de

initComponents();

do codigo do Netbeans

((javax.swing.JSpinner.DefaultEditor) TeuObjetojSpinner.getEditor()).getTextField().addKeyListener(
                new java.awt.event.KeyListener() {

                    public void keyTyped(java.awt.event.KeyEvent e) {
                        //Exemplo
                        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                            JOptionPane.showMessageDialog(null, "Pressionou ENTER");
                        }
                    }

                    public void keyPressed(java.awt.event.KeyEvent e) {
                    }

                    public void keyReleased(java.awt.event.KeyEvent e) {
                    }
                });

vlwwwwwwwwww


ambuzr:

Funcionou perfeitamente. A diferença é que coloquei o código não depois do initComponents() mas sim dentro. Mais especificamente na parte em que o NB a personalização do código depois da inicialização do componente.

Grato,

Rafael U. C. Afonso

D

Boa dica ambuzr! Eu estava tentando pegar esse TextField! Com isso consegui resolver outro problema que eu tinha (desabilitar só a TextField do Spinner). Valeu!

Criado 22 de março de 2010
Ultima resposta 24 de mar. de 2010
Respostas 6
Participantes 3