Hendra
Hendra

Reputation: 43

Key binding in JTable editor

I found keybinding topic (JTable Key Bindings) similar to this. I learned that its keybinding is bound to the table not the editor.

My goal is any input on editor ending with VK-ENTER, it executes action pindah (which is adding new row and set cursor blinking on new row). I'm sorry, I failed to learn from that example.

Is there a way for that?

Here is my code (excluding the import as Eclipse will suggest it automatically):

public class Fpos extends JFrame 
{
public static void main(String[] args) 
{
    EventQueue.invokeLater(new Runnable() 
    {
        public void run() 
        {
            try 
            {
                Fpos frame = new Fpos();
                frame.setVisible(true);
                frame.setLocationRelativeTo(null);  //make frame center of screen                   
            } catch (Exception e) {e.printStackTrace();}
        }
    });
}

public Fpos() 
{
    //create Jpanel
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(10, 10, 1300, 700);
    JPanel contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    contentPane.setLayout(null);
    //create label TOTAL
    JLabel lblTotal = new JLabel("TOTAL : Rp.");                
    lblTotal.setFont(new Font("Wide Latin", Font.PLAIN, 30));
    lblTotal.setBounds(33, 25, 312, 31);
    contentPane.add(lblTotal);
    //create label Total Amount
    JLabel lblNewLabel = new JLabel("123,456,789");
    lblNewLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    lblNewLabel.setFont(new Font("Wide Latin", Font.PLAIN, 60));
    lblNewLabel.setBounds(583, 19, 659, 61);
    contentPane.add(lblNewLabel);
    //create jtable in scrollpane
    String[] columnNames = {"PLU", "NAME", "UOM", "QTY", "PRICE","AMOUNT"};
        Object[][] data = {{"", "", "", "", "", ""}};
         DefaultTableModel model = new DefaultTableModel(data, columnNames);
     JTable table = new JTable(model);                  
     table.setFont(new Font("Tahoma", Font.PLAIN, 20));
     table.setRowHeight(25);
     JScrollPane sp=new JScrollPane(table);             
     sp.setBounds(25,100,1240,556);
     contentPane.add(sp);
     //set column width
     TableColumnModel columnModel = table.getColumnModel();
     short a[] = {150,540,50,150,150,200};
     for(byte i=0;i<6;i++) { columnModel.getColumn(i).setPreferredWidth(a[i]); }
     //render column format left alignment
     for(byte i=0;i<3;i++) {table.getColumnModel().getColumn(i).setCellRenderer(new TextTableCellRenderer());}
     //render column format ###,##0 right alignment
     for(byte i=3;i<6;i++) {table.getColumnModel().getColumn(i).setCellRenderer(new NumberTableCellRenderer());}
     //make cursor blinking on selected cell + select all cell value
    SwingUtilities.invokeLater(new Runnable()
    {
        public void run() 
        {
             table.changeSelection(0, 0, false, false);
             if (table.editCellAt(0, 0))
             {
                Component editor = table.getEditorComponent();
                editor.setFont(new Font("Tahoma", Font.PLAIN, 20));
                editor.requestFocusInWindow();
                ((JTextComponent)editor).selectAll(); //select all cell value                   

                //key binding
                Action pindah = new AbstractAction() 
                {
                    @Override
                    public void actionPerformed(ActionEvent e) 
                    {
                         //add row at last row
                         model.addRow(data);
                        //i want to add new blank row but somehow there is value on column 0, so I have to set it blank. If you have a solution on this, you're very welcome
                         model.setValueAt("", model.getRowCount()-1, 0);
                         //make cursor blinking on selected cell + select all cell value
                            SwingUtilities.invokeLater(new Runnable()
                            {
                                public void run() 
                                {
                                     table.changeSelection(0, 0, false, false);
                                     if (table.editCellAt(model.getRowCount()-1, 0))
                                     {
                                        Component editor = table.getEditorComponent();
                                        editor.setFont(new Font("Tahoma", Font.PLAIN, 20));
                                        editor.requestFocusInWindow();
                                        ((JTextComponent)editor).selectAll(); //select all cell value                   
                                     }
                                }
                            });              
                    }
                };
                ((JComponent) editor).getInputMap().put(KeyStroke.getKeyStroke((char) KeyEvent.VK_ENTER), "pindah");
                ((JComponent) editor).getRootPane().getActionMap().put("pindah", pindah);


            }
         }
    });              

}

//  render column format left alignment
 public class TextTableCellRenderer extends DefaultTableCellRenderer 
    {public TextTableCellRenderer() {{setHorizontalAlignment(JLabel.LEFT);}} }
//  render column format to ###,##0
 public class NumberTableCellRenderer extends DefaultTableCellRenderer 
 {         
     public NumberTableCellRenderer() {setHorizontalAlignment(JLabel.RIGHT);}
         @Override
         public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 
         {
                 if (value instanceof Number) {value = NumberFormat.getNumberInstance().format(value);}
                 return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
         }
 }
}

Upvotes: 0

Views: 300

Answers (1)

camickr
camickr

Reputation: 324108

Not an answer but several comments about your code.

First you need to understand about the Event Dispatch Thread (EDT). Updates to GUI components need to be done on the EDT.

Normally you don't need to keep nesting SwingUtilities.invokeLater() code since you do create your GUI on the EDT.

The reason we needed to add the invokeLater(...) to make the first cell editable and have the cursor blinking is that you can't set focus on a component if the frame is not visible. So the invokeLater(...) allows us to add code to the end of the EDT so it executed after the setVsible(...) statement in your main() method.

So, if you do want to use Key Bindings you could just set all the Key Bindings in the constructor of your Fpos class.

However, I don't know the proper solution for this current requirement.

Currently, an ActionListener is added to the JTextField that is used as the cell editor. When you press the Enter key the listener is invoked and the stop cell editing logic of the table is invoked, which means the value in the editor is added to the TableModel and the cell editor is removed from the table.

So you can't just simply add a Key Binding to the editor since you need this default behaviour to occur.

I guess you could create a custom cell editor. Then in the ActionListener you can add your additional requirements.

Upvotes: 2

Related Questions