Começar edição em célula da JTable [RESOLVIDO]

1 resposta
D

Pessoal, na minha JTable tenho a coluna “Duração” (em que o usuário vai inserir a duração em mm:ss de um evento) com o seguinte cell editor:

public class ColunaDuracao extends AbstractCellEditor implements TableCellEditor {
    JComponent component;    
    
    @Override
    public Component getTableCellEditorComponent(JTable table, Object value,
            boolean isSelected, int rowIndex, int vColIndex) {
        
        MaskFormatter duracaoFormat = null;
        try {
            duracaoFormat = new MaskFormatter("##:##");            
            
            SwingUtilities.invokeLater(new Runnable() {  
                @Override
                public void run() {                      
                    ((JFormattedTextField)component).setText("0"); //quando for digitar na célula, aparece um "0"
                    ((JFormattedTextField)component).setCaretPosition(1); //começa a digitar depois do "0"
                }  
            });
            
        } catch (ParseException ex) {
            Logger.getLogger(ColunaDuracao.class.getName()).log(Level.SEVERE, null, ex);
        }
            
        component = new JFormattedTextField(duracaoFormat);                                        
        ((JFormattedTextField)component).setText((String)value);
        
        return component;
    }   

    @Override
    public Object getCellEditorValue() {                        
        return ((JFormattedTextField)component).getText();
    }
}

Minha dúvida é a seguinte:
Com o código das linhas 12 a 18, se o usuário for até a coluna “Duração” usando as teclas direcionais ou TAB e começar a digitar nela, o zero é inserido normalmente, porém, o número que ele teclou não é; é como se inserir o primeiro zero desse um evt.consume() na tecla. Depois disso, se pressionar qualquer tecla numérica novamente, o valor é inserido na frente do primeiro zero.
Se eu clicar diretamente na célula da coluna “Duração”, aí sim, o primeiro zero aparece, o cursor piscando depois do zero e recebe qualquer valor numérico.
Esse primeiro zero é pra que o usuário não precise digitá-lo, mas há ocasiões em que ele deverá ser apagado, por isso não posso colocálo na máscara.
Quero que quando for digitar na célula (sem clicar nela antes), o zero seja inserido e o valor digitado na frente do zero, sem ter que teclar 2 vezes. Tentei até agora de várias maneiras que não deram o resultado desejado. Tentei fazer com que o “cursor aparecesse” quando pressionasse alguma tecla numa célula da coluna “Duração” mas também não consegui.
Se alguém tiver uma ideia que possa me ajudar, me diga por favor. Vlw!

1 Resposta

D

Caso alguém precise de algo semelhante um dia, resolvi assim:

public class ColunaDuracao extends AbstractCellEditor implements TableCellEditor {
    private JComponent component; //componente que irá manipular a edição da célula
            
    // evento chamado quando a célula começa a ser editada
    @Override
    public Component getTableCellEditorComponent(JTable table, Object value,
            boolean isSelected, int rowIndex, int vColIndex) {
                        
        PropertyChangeListener propertyListener=new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {   
                if(validarCelula()==false) //se a célula não estiver preenchida
                    ((JFormattedTextField)component).setText("0"); //insere um zero no começo
                else { //se a célula estiver preenchida
                    ((JFormattedTextField)component).setCaretPosition(0); //posiciona o cursor no início do texto
                }
            }
        };        
        
        FocusListener focusListener=new FocusListener() {
            @Override
            public void focusGained(FocusEvent e) {
                if(validarCelula()==false) //se a célula não estiver preenchida
                    ((JFormattedTextField)component).setCaretPosition(1); //posiciona o cursor depois do zero
                else //se estiver preenchida
                    ((JFormattedTextField)component).setCaretPosition(0);
            }

            @Override
            public void focusLost(FocusEvent e) {
                
            }
        };
        
        KeyListener keyListener=new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {
                
            }

            @Override
            public void keyPressed(KeyEvent e) {
                if(e.getKeyChar()==KeyEvent.VK_ENTER) //se pressionar enter
                    stopCellEditing(); //pára a edição da célula
            }

            @Override
            public void keyReleased(KeyEvent e) {
                
            }
        };        
        
        MaskFormatter duracaoFormat = null;
        try {
            duracaoFormat = new MaskFormatter("##:##");
            component = new JFormattedTextField(duracaoFormat); 
            component.addPropertyChangeListener(propertyListener);             
            component.addFocusListener(focusListener);
            component.addKeyListener(keyListener);
        } catch (ParseException ex) {
            Logger.getLogger(ColunaDuracao.class.getName()).log(Level.SEVERE, null, ex);
        }                               
                        
        ((JFormattedTextField)component).setText((String)value);
        
        return component; //retorna o componente configurado
    }        
    
    //verifica se todos os caracteres da célula foram preenchidos:
    public boolean validarCelula() {
        Pattern padrao = Pattern.compile("\\d\\d:\\d\\d"); //2 dígitos seguidos de ':' e mais 2 dígitos                
        Matcher pesquisa = padrao.matcher(((JFormattedTextField)component).getText());  
        
        if(pesquisa.matches())
            return true;
        else
            return false;
    }
    
    //método invocado quando a edição é terminada:
    @Override
    public Object getCellEditorValue() {                        
        if (validarCelula()==false) //se a comparação com a expressão não for válida
            return "00:00";
                
        else
            return ((JTextField)component).getText(); //valor que será inserido na célula            
    }
}
Criado 8 de dezembro de 2011
Ultima resposta 9 de dez. de 2011
Respostas 1
Participantes 1