使用 TableCellEditor 时如何获取鼠标单击位置的组件?

发布于 2024-12-22 18:42:48 字数 5895 浏览 2 评论 0原文

我在表格单元格中使用带有多个 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 行时)。

使用 TableCellEditorTableCellRenderer 时如何获取用户单击的组件?


以下是完整示例:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

甜宝宝 2024-12-29 18:42:48

不完全确定我明白出了什么问题(只要让我知道我是否关闭,这样我就可以删除它:-)

假设您想要在鼠标(单击/按下)下获取触发启动的“真实”组件编辑时,诀窍是在将编辑器添加到其父级之后进行转换(从父级坐标到编辑器坐标)。这对 shouldSelectCell 是有保证的,但对 isCellEditable 则不然(后者在之前被调用

) -edit-even-if-shouldselectcell-return-false/8279716#8279716">最近的答案在树的上下文中(应该类似足够了)有一些可运行的例子。这是相关的片段:

/**
 * 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
            ....
        }
    });
}

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:

/**
 * 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
            ....
        }
    });
}
獨角戲 2024-12-29 18:42:48

这不是您问题的答案,而是您看到的结果的解释: findComponentAt() 返回 null 因为“请求的点没有子组件。 ” MyCellPanel 位于 JTable 使用 CellRendererPane 来加速渲染。 此处有一个如何使用它的示例。

This is not an answer to your question but an explanation of the result you see: findComponentAt() returns null because "there is no child component at the requested point." MyCellPanel is located on a CellRendererPane used by JTable to speed rendering. There's an example of how it's used here.

絕版丫頭 2024-12-29 18:42:48

您可以从单击的点获取表格的行和列。然后调用同一个渲染器的 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文