0

My textField is visible when textField.setBounds(27, 60, 150, 25) but I want it visible when textField.setBounds(27, 120, 150, 25). How to put textField over JTable (hovering on top of JTable) and still visible?

Here is my code:

import java.awt.EventQueue;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;
import javax.swing.JLabel;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.SwingConstants;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import java.awt.Color;

public class Fpos extends JFrame 
{
    private JTextField textField;
    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 lbl1 = new JLabel("TOTAL : Rp.");                
        lbl1.setBounds(33, 25, 312, 31);
        lbl1.setFont(new Font("Wide Latin", Font.PLAIN, 30));
        contentPane.add(lbl1);
        //create label Total Amount
        JLabel lblTotal = new JLabel("123,456,789");
        lblTotal.setBounds(583, 19, 659, 61);
        lblTotal.setHorizontalAlignment(SwingConstants.RIGHT);
        lblTotal.setFont(new Font("Wide Latin", Font.PLAIN, 60));
        contentPane.add(lblTotal);
        //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]); }
        //virtual table cell editor
         textField = new JTextField();       
         textField.setBackground(Color.CYAN);
         textField.setBounds(27, 60, 150, 25);       
         contentPane.add(textField);                         
         textField.requestFocus();
         //keybinding bound to texField starting here
         //keybinding for enter key
        Action enter = new AbstractAction() 
        {
            @Override
            public void actionPerformed(ActionEvent e) 
            {
                /* It'll be quite lot of code here later, let me summarize them:
                 * 1. query from database with textfield value
                 * 2. setvalue table from resultset
                 * 3. sum all value from column 5 and set its value to lblTotal
                 * 4. adding row 
                 * 5. move textfield over new row column 0 of the jtable (new item is ready for input by barcode scanner again)
                 */  
                //add new blank row at last row
                 model.addRow(data);
                 model.setValueAt("", model.getRowCount()-1, 0);
            }
        };
        textField.getInputMap().put(KeyStroke.getKeyStroke((char) KeyEvent.VK_ENTER), "enter");
        textField.getActionMap().put("enter", enter);
         //keybinding for up key
        Action up = new AbstractAction() 
        {
            @Override
            public void actionPerformed(ActionEvent e) 
            {
                //move textfield to row-1 column  0
            }
        };
        textField.getInputMap().put(KeyStroke.getKeyStroke((char) KeyEvent.VK_UP), "up");
        textField.getActionMap().put("up", up);
         //keybinding for down key
        Action down = new AbstractAction() 
        {
            @Override
            public void actionPerformed(ActionEvent e) 
            {
                //move textfield to row+1 column  0 
            }
        };
        textField.getInputMap().put(KeyStroke.getKeyStroke((char) KeyEvent.VK_DOWN), "down");
        textField.getActionMap().put("down", down);
        //keybinding for F3 key
        Action  f3 = new AbstractAction() 
        {
            @Override
            public void actionPerformed(ActionEvent e) 
            {
                //delete current row (delete item) and recalculate for lblTotal
            }
        };
        textField.getInputMap().put(KeyStroke.getKeyStroke((char) KeyEvent.VK_ESCAPE), "f3");
        textField.getActionMap().put("f3", f3); 
        //keybinding for F1 key, show new frame/jpane for cashier search item by name when item code (textfield) not available 
        //keybinding for F9 key, show new frame/jpane for payment method whether cash or card
        //keybinding for F7 key, show new frame/jpane for reprint history transaction by input transaction id (with new textfield)          
    }
}
Hendra
  • 43
  • 9
  • Why you need this??? – Sergiy Medvynskyy Nov 27 '17 at 07:02
  • This code is for POS system which 80% of input is by barcode scanner and 20% by keyboard, 0% by mouse. This textfield will replace table cell editor and will be the only one that has focus. My requirement is textfield will receive keybinding (about 8 input map including Enter) but Default or custom cell editor cant use keybinding. So the plan is textfield will hover over Jtable on selected table cell (of cuz I set its size to match table cell size) working as if it's table cell editor. – Hendra Nov 27 '17 at 08:36
  • Nice question(s). Best though, to limit each thread to a single question (e.g in case a 'key bindings' expert decided not to answer because they had no idea about the other question.) Since I'm expert on neither, I'll leave it to those that are. – Andrew Thompson Nov 27 '17 at 10:01
  • *"How to put textField over JTable (hovering on top of JTable) and still visible?*" - You don't - you stop using `null` layouts and you start using editable tables - which they are designed for – MadProgrammer Nov 27 '17 at 10:11
  • Start by taking a look at [How to use tables](https://docs.oracle.com/javase/tutorial/uiswing/components/table.html) – MadProgrammer Nov 27 '17 at 10:13
  • The issue with your key bindings is this: `textField.getRootPane().getActionMap()`, it should be `textField.getActionMap()` - The `InputMap` and `ActionMap` are related, an key event triggers the look up in the `InputMap` of the component which triggered it, it then looks up the associated acton in the component's `ActionMap`, but you set the `InputMap` up on the text field and the `ActionMap` on the root pane, disconnecting the two – MadProgrammer Nov 27 '17 at 10:17
  • @MadProgrammer, maybe you want to check out the OP's original question: https://stackoverflow.com/questions/47447780/key-binding-in-jtable-editor (basically they want to handle the Enter key on the editor to add a new row of data). I wasn't sure of the answer. I suggested the editor needed to be customized, but they came up with this approach instead. – camickr Nov 27 '17 at 15:32
  • @camickr I’d have to think about it, but, a key binding on the table itself might be the place to start – MadProgrammer Nov 27 '17 at 18:50
  • @MadProgrammer, a text field already has a default key binding for the Enter key, so you can't add a second binding for the table since the "when-in-focus" binding will have priority. That is why I think you need a custom editor? – camickr Nov 27 '17 at 20:40
  • @camickr Can't remember how we set up continuous editing, I know it included tab, might have included enter, I'll need to dig out the old code (if I still have it) – MadProgrammer Nov 27 '17 at 20:52
  • @andrew, I see, to limit 1 question per thread. – Hendra Nov 28 '17 at 04:11
  • @MadProgrammer, thank you for removing getrootpane, I really missed it. I've re-edited the question and there are more explanation at keybinding section to show where the code flow will be. – Hendra Nov 28 '17 at 04:15
  • @camickr, I came up with this approach since I'm not sure if custom editor can handle lot of keybinding. Please check my revise code here, I've placed more explanations on keybinding section, there are sum more keybinding added and all are bound to cell editor. Is it still possible using custom editor? Please advise – Hendra Nov 28 '17 at 04:29
  • I know it can't handle more than one key binding. That was not the suggestion. The suggestion was to customize the default cell editor to add your extra logic. I don't see any reason it wouldn't work. But I guess you would need to pass in the table as a parameter to your custom key editor class. Then after the cell editor invokes "stop editing" on the cell you would add your custom code. I would guess you would want to extend the "GenericEditor" class defined in the JTable class. So you basically need to override the `actionPerformed(...)` method to add your custom code. – camickr Nov 28 '17 at 04:34
  • @camickr, "stop editing" is just invoked by Enter key only (please correct me if I'm wrong), but there are F3, F9, up and down keystroke too which is hit before "stop editing" invoked. So after pressing F3, I have to press Enter too to invoke "stop editing", don't I? I'm sorry, I'm not quite understand. – Hendra Nov 28 '17 at 04:59
  • Yes there are many ways to stop editing on a cell. But your question is about when you use the `Enter` key, so the other keys don't matter. You need to customize the behaviour of the Enter key. The code for the Enter key is invoked by the default cell editor. So you need to look at the source code for the DefaultCellEditor class and the GenericEditor class which extends DefaultCellEditor to see what code is executed when the Enter key is pressed. Then you need to add your extra code. – camickr Nov 28 '17 at 05:19
  • @camickr, welll I really hope that textField can hover over JTable, that's the least code needed and solve this requirement so better let this post still open so may someone found the solution. But I'll look at the source code for the DefaultCellEditor class and GenericEditor class too just in case there is absolutely no way to make textField hover over Jtable. Thank you. – Hendra Nov 28 '17 at 08:35
  • @camickr I've used `WHEN_ANCESTOR_OF_FOCUSED_COMPONENT` on a `JTable` and bound [Enter], [Tab], [Escape], [Down/Up Arrow] keys in the past. I've done this to introduce a continuous editing process, so pressing [Enter]/[Tab] will move you to the next editable cell, or if supplied, allow you to determine if a new row should be added when you reach the last cell – MadProgrammer Nov 28 '17 at 11:09
  • @Hendra *" really hope that textField can hover over JTable, that's the least code needed and solve this requirement"* - I think you'll find that the customising a `TableCellEditor` will produce less code then re-inventing the wheel – MadProgrammer Nov 28 '17 at 11:10
  • @MadProgrammer, `I've used WHEN_ANCESTOR_OF_FOCUSED_COMPONENT on a JTable and bound [Enter], [Tab], [Escape], [Down/Up Arrow] keys in the past.` - yes, I have done that as well. It works fine as long as the table is NOT editing a cell. I would like to see how you might handle the Enter key on the editor and on the table at the same time so that both Actions are invoked with a single key stroke? In any case I added a potential solution. – camickr Nov 28 '17 at 16:31
  • @camickr Didn't seem to have any issues from memory - I'll see if I consolidate the API - But the point of the the (continuous editing) API was to lift the responsibility from the field and place it on the table, so it didn't matter what editor was been used, made it much simpler to customise. – MadProgrammer Nov 28 '17 at 20:17
  • @MadProgrammer, I see, I'm always open with any approach/ways as long as the requirement is met. The least code the better. – Hendra Nov 28 '17 at 22:38
  • @MadProgrammer, *stop using null layout*, I've read the disadvantage of this absolute layout due to resizing, I'll change to 1 of other 8 layouts and grid or form layout seems a good canditate to meet this required layout. Thank you for the suggestion. – Hendra Nov 29 '17 at 03:34

1 Answers1

0

With a little more thought, I think all you need to do is replace the default key binding on the editor with a key binding of your own:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;

public class TableEnter extends JPanel
{
    public TableEnter()
    {
        JTable table = new JTable(5, 5);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane( table );
        add( scrollPane );

        Action enterAction = new AbstractAction()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                JTextField textField = (JTextField)e.getSource();
                JTable table = (JTable)textField.getParent();

                if (table.isEditing())
                    table.getCellEditor().stopCellEditing();

                //  add your custom logic here

                int row = table.getSelectedRow();
                int column = table.getSelectedColumn();
                System.out.println(row + " : " + column);
            }
        };

        DefaultCellEditor editor = (DefaultCellEditor)table.getDefaultEditor(Object.class);
        JTextField textField = (JTextField)editor.getComponent();

        final String enterKey = "VK_ENTER";
        KeyStroke enter = KeyStroke.getKeyStroke("pressed ENTER");
        textField.getInputMap().put(enter, enterKey);
        textField.getActionMap().put(enterKey, enterAction);
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.add( new TableEnter() );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater( () -> createAndShowGUI() );
/*
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
*/
    }
}
camickr
  • 321,443
  • 19
  • 166
  • 288
  • This is a perfect solution, it solves multi keybinding on text editor with the least code / rows. Also nice code cutting trick on invokeLater, it saves 3 rows n 31 chars. And stopediting on keybinding too cuz practically editing will be stopped by logic code. 3 tricks in 1 answer. Really perfect solution for me. Thank you very much Camickr. I'll bury this overlapping textfield on jtable approach. Sorry I come from VB6 and chose to migrate to Java instead of VB.net. Just for information, in all 9 java layout, does it really forbid overlapping components? – Hendra Nov 29 '17 at 03:22
  • on this case overlapping component like textfield over jtable – Hendra Nov 29 '17 at 03:49
  • `I'll bury this overlapping textfield on jtable approach.` - that is what an editor is. It is just a JTextField displayed on top of the table. The point we were trying to make is "don't reinvent the wheel". Instead of creating an editor from scratch, just use the default editor and customize its behaviour. Or in this case we were able to replace the key binding to achieve the desired result. – camickr Nov 29 '17 at 04:04
  • I see your point, your solution is actually also textfield displayed on top of table too. The problem is only multiple keybinding on editor which I failed to solve and then tried to create another textfield on top of Jtable which is already supplied by default editor. This is a very good lesson for me understanding default cell editor more. Thank you camickr. – Hendra Nov 29 '17 at 07:00
  • Hi all, I'm stuck in my code again and post it in new post. Please feel free to check it out. https://stackoverflow.com/questions/47806783/running-code-for-frame-1-from-frame-2. Thank you – Hendra Dec 14 '17 at 06:07