使用TableCellEditor时,如何在鼠标单击位置获取组件?
我在表格单元格中使用自定义TableCellRenderer
和多个JFormattedTextField
。 我使用与TableCellEditor
相同的组件。 现在我需要知道用户单击的JFormattedTextField
,以及此字段中的位置(可以使用viewToModel
完成)。
使用自定义TableCellEditor
,从鼠标单击中获取Point
的唯一方法是CellEditor
的isCellEditable(EventObject e)
方法。 给出的Point
在父坐标系中。
anEvent在调用组件坐标系中。
但是如何在单击的坐标上获取组件? 我尝试过使用findComponentAt(Point p)
但它为我返回null
。
这是我测试过的一些代码:
@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; }
组件位置的值editor.getLocation();
给出y坐标的几乎随机值(例如,当在表中使用5行时)。
在使用TableCellEditor
和TableCellRenderer
时,如何获取用户单击的组件?
这是一个完整的例子:
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, Object value, boolean isSelected, int row, 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(Box.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 values = new ArrayList(); 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(); } }); } }
不完全确定我明白出了什么问题(只是让我知道,如果我关闭,所以我可以删除这个:-)
假设您希望获得触发编辑开始的鼠标(单击/按下)下的“真实”组件,诀窍是在将编辑器添加到其父级之后进行转换(从父级到编辑器坐标)。 这对于shouldSelectCell是有保证的,但不是对于isCellEditable(后者之前被调用)
最近在树的上下文中的答案 (应该足够相似)有一些可运行的例子。 这是相关的片段:
/** * 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 fi findComponent .... } }); }
这不是你的问题的答案,而是对你看到的结果的解释: findComponentAt()
返回null
因为“在请求的点上没有子组件”。 MyCellPanel
位于JTable
用于加速渲染的CellRendererPane
。 这里有一个如何使用它的例子。
您可以从单击的点获取表格的行和列。 然后调用相同的渲染器的getTableCellRendererComponent方法来获取渲染器组件。 然后正确的点从y减去前一行的高度,从x减去先前单元格的宽度。 然后获得渲染组件的正确子项。