使用 TableCellEditor 时如何获取鼠标单击位置的组件?
我在表格单元格中使用带有多个 JFormattedTextField
的自定义 TableCellRenderer
。我使用与 TableCellEditor
相同的组件。现在我需要知道用户在什么 JFormattedTextField
中单击,以及该字段中的哪个位置(可以使用 viewToModel
完成)。
使用自定义 TableCellEditor
时,通过鼠标单击获取 Point
的唯一方法是 isCellEditable(EventObject e)
中的方法单元格编辑器
。给定的点位于父坐标系中。
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<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();
}
});
}
}
I use a custom TableCellRenderer
with multiple JFormattedTextField
in the table cells. I use the same component as TableCellEditor
. Now I need to know in what JFormattedTextField
the user clicked, and also where in this field (can be done with viewToModel
).
When using a custom TableCellEditor
, the only way to get the Point
from the mouse click is the isCellEditable(EventObject e)
method in CellEditor
. The Point
given is in the parents coordinate system.
anEvent is in the invoking component coordinate system.
But how can I get the component at the clicked coordinate? I have tried with findComponentAt(Point p)
but it returns null
for me.
Here is some code I have tested with:
@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;
}
The values for the component's location editor.getLocation();
gives almost random values for the y-coordinate (e.g. when using 5 rows in the table).
How can I get the component the user clicked on when using a TableCellEditor
and a TableCellRenderer
?
Here is a full 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,
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<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();
}
});
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不完全确定我明白出了什么问题(只要让我知道我是否关闭,这样我就可以删除它:-)
假设您想要在鼠标(单击/按下)下获取触发启动的“真实”组件编辑时,诀窍是在将编辑器添加到其父级之后进行转换(从父级坐标到编辑器坐标)。这对 shouldSelectCell 是有保证的,但对 isCellEditable 则不然(后者在之前被调用
) -edit-even-if-shouldselectcell-return-false/8279716#8279716">最近的答案在树的上下文中(应该类似足够了)有一些可运行的例子。这是相关的片段:
Not entirely sure I understand what's going wrong (just let me know if I'm off, so I can delete this :-)
Assuming you want to get the "real" component under the mouse (click/press) which triggered the start of editing, the trick is to do the conversion (from parent to editor coordinates) after the editor is added to its parent. That's guaranteed for shouldSelectCell, but not for isCellEditable (the latter being called before)
A recent answer in the context of a tree (should be similar enough) has some runnable example. Here's the relevant snippet:
这不是您问题的答案,而是您看到的结果的解释:
findComponentAt()
返回null
因为“请求的点没有子组件。 ”MyCellPanel
位于JTable
使用CellRendererPane
来加速渲染。 此处有一个如何使用它的示例。This is not an answer to your question but an explanation of the result you see:
findComponentAt()
returnsnull
because "there is no child component at the requested point."MyCellPanel
is located on aCellRendererPane
used byJTable
to speed rendering. There's an example of how it's used here.您可以从单击的点获取表格的行和列。然后调用同一个渲染器的 getTableCellRendererComponent 方法来获取渲染器组件。然后更正点,从 y 中减去前一行的高度,从 x 中减去前一个单元格的宽度。然后获取渲染组件的正确子级。
You can get the table's row and column from the clicked point. Then call the same renderer's getTableCellRendererComponent method to get renderer component. Then correct point subtracting previous rows' heights from y and previous cells' widths from x. Then get proper child of rendered component.