Java – how do I get components at the mouse click position when using TableCell editor?
I use a custom tablecellrenderer and multiple jformattedtextfields in table cells I use the same components as TableCell editor Now I need to know the jformattedtextfield that the user clicked and the location in this field (which can be done using viewtomodel)
When using a custom tablecelleditor, the only way to get a point from a mouse click is the iscelleditable (eventobject E) method in celleditor The given point is in the parent coordinate system
But how do I get the component at the clicked coordinates? I tried findcomponentat (point P), but it returned null for me
Here are some of the codes I have tested:
@Override public boolean isCellEditable(EventObject e) { if(e instanceof MouseEvent) { MouseEvent ev = (MouseEvent)e; Point p = ev.getPoint(); // gives strange values Point p3 = editor.getLocation(); // x: 0 y: 0 Point tp = ((JTable)e.getSource()).getLocation(); // these returns null Component c1 = renderer.findComponentAt(p); Component c2 = editor.findComponentAt(p); System.out.println("Click at " + p + " editor at: " + p3); } return true; }
Value of component location editor getLocation(); Give an almost random value for the Y coordinate (for example, when 5 rows are used in the table)
When using tablecelleditor and tablecellrenderer, how to get the component clicked by the user?
This is a complete example:
public class FormattedTableEditDemo extends JFrame { public FormattedTableEditDemo() { MyTableModel model = new MyTableModel(); MyTableCellEditorAndRenderer cellEditorAndRenderer = new MyTableCellEditorAndRenderer(); JTable table = new JTable(model); table.setDefaultRenderer(BigDecimal.class,cellEditorAndRenderer); table.setDefaultEditor(BigDecimal.class,cellEditorAndRenderer); table.setRowHeight(40); add(new JScrollPane(table)); pack(); setDefaultCloSEOperation(EXIT_ON_CLOSE); setVisible(true); } class MyTableCellEditorAndRenderer extends AbstractCellEditor implements TableCellEditor,TableCellRenderer { MyCellPanel editor = new MyCellPanel(); MyCellPanel renderer = new MyCellPanel(); @Override public Object getCellEditorValue() { return editor.getValue(); } @Override public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int column) { renderer.setValue(value); return renderer; } @Override public Component getTableCellEditorComponent(JTable table,int column) { editor.setValue(value); return editor; } @Override public boolean shouldSelectCell(EventObject e) { return false; } @Override public boolean isCellEditable(EventObject e) { if(e instanceof MouseEvent) { MouseEvent ev = (MouseEvent)e; Point p = ev.getPoint(); // gives strange values Point p3 = editor.getLocation(); // x: 0 y: 0 Point tp = ((JTable)e.getSource()).getLocation(); // these returns null Component c1 = renderer.findComponentAt(p); Component c2 = editor.findComponentAt(p); System.out.println("Click at " + p + " editor at: " + p3); } return true; } } class MyCellPanel extends JPanel { jformattedtextfield field1 = new jformattedtextfield(); jformattedtextfield field2 = new jformattedtextfield(); public MyCellPanel() { field1.setColumns(8); field2.setColumns(8); field2.setValue(new BigDecimal("0.00")); setLayout(new BorderLayout()); add(field1,BorderLayout.WEST); add(@R_408_2419@.createHorizontalStrut(30)); add(field2,BorderLayout.EAST); } public Object getValue() { return field1.getValue(); } public void setValue(Object value) { field1.setValue(value); } } class MyTableModel extends AbstractTableModel { List<BigDecimal> values = new ArrayList<BigDecimal>(); public MyTableModel() { // test values values.add(new BigDecimal("37.00")); values.add(new BigDecimal("4305.90")); values.add(new BigDecimal("386.04")); values.add(new BigDecimal("3486.58")); values.add(new BigDecimal("6546.45")); } @Override public int getColumnCount() { return 1; } @Override public int getRowCount() { return values.size(); } @Override public Object getValueAt(int row,int column) { return values.get(row); } @Override public boolean isCellEditable(int row,int column) { return true; } @Override public Class<?> getColumnClass(int column) { return BigDecimal.class; } } public static void main(String[] args) { SwingUtilities.invokelater(new Runnable() { @Override public void run() { new FormattedTableEditDemo(); } }); } }
Solution
Not quite sure I understand what's wrong (just let me know if I close, so I can delete this: -)
Suppose you want to get the "real" component under the mouse (click / Press) that triggers the start of editing. The trick is to convert (from parent to editor coordinates) after adding the editor to its parent This is guaranteed for shouldselectcell, but not for iscelleditable (which was called earlier)
There are some runnable examples of recent answers (which should be similar enough) in the context of the tree This is a related fragment:
/** * At this point in time the editing component is added to the table (not documented!) but * table's internal cleanup might not yet be ready */ @Override public boolean shouldSelectCell(EventObject anEvent) { if (anEvent instanceof MouseEvent) { redirect((MouseEvent) anEvent); } return false; } private void redirect(final MouseEvent anEvent) { SwingUtilities.invokelater(new Runnable() { @Override public void run() { MouseEvent ev = SwingUtilities.convertMouseEvent(anEvent.getComponent(),anEvent,editor); // at this point you have the mouse coordinates in the editor's system // do stuff,like f.i. findComponent .... } }); }