如何为 DefaultCellEditor 模拟 "onStartCellEditing"

how do I simulate "onStartCellEditing" for DefaultCellEditor

CellEditorListener 有 "editingStopped" 和 "editingCancelled"。但是,当单元格编辑会话开始时,我该如何实现一段需要 运行 的代码?

一个典型的例子可能是当您开始编辑时,您希望 JTextField 编辑器组件的文本转到 selectAll()。我很想认为要做的事情是重写 DefaultCellEditor 的一种方法,例如 getTableCellEditorComponent 或 getCellEditorValue 或 getComponent,但其中 none 明确表示它们在编辑会话开始时被调用。

相反,如果我们正在编辑,我们确实知道 JTable.getCellEditor return 是编辑器,但如果不是,则为 null。这是因为在编辑开始时组件被做成了JTable 的子对象。它还似乎在编辑会话开始时获得焦点,因此您可能会考虑将 FocusListener 添加到编辑器组件(JTextField 等)。但这有保证吗?此外,在编辑会话期间可能会失去焦点,然后 return。

有一种侦听此编辑器组件的 "addition"(作为子对象)的方法:ContainerListener。除非有人告诉我不同​​的说法,否则这似乎是接到电话通知编辑会话已经开始的最直接、最合理的方式。但是没有更直接的方法似乎很奇怪...

A typical example might be where you want the text of a JTextField editor component to go selectAll() when you start editing.

编辑开始后,您可以将 JTable 的 editCellAt(...) 方法重写为 select 文本:

@Override
public boolean editCellAt(int row, int column, EventObject e)
{
    boolean result = super.editCellAt(row, column, e);
    final Component editor = getEditorComponent();

    if (editor != null && editor instanceof JTextComponent)
    {
        ((JTextComponent)editor).selectAll();

        if (e == null)
        {
            ((JTextComponent)editor).selectAll();
        }
        else if (e instanceof MouseEvent)
        {
            SwingUtilities.invokeLater(new Runnable()
            {
                public void run()
                {
                    ((JTextComponent)editor).selectAll();
                }
            });
        }
    }

    return result;
}

Rob Camick 的回答很好,但我还有另一个答案供 "completists" 细读。

我使用 Jython,但它应该足够简单以供 Java 人理解。在 Python/Jython 中,您可以向(几乎)任何对象添加任意 "attributes"。因此,在 editCellAt 中,我添加了一个属性 "start_editing",然后向添加到 JTextField 编辑器组件的插入符号侦听器发出会话刚刚开始的信号。如果插入点和标记相等(折叠),如果开始编辑的点击计数 == 2,并且如果编辑器具有 "start_editing" 属性,则您 select-all(再次),并且您还删除了 "start_editing" 属性...它可以工作(!),而无需生成新的 Runnable。

class DatesTable( javax.swing.JTable ):
    def editCellAt(self, row, column, event_obj ):
        result = self.super__editCellAt( row, column, event_obj )
        if self.editorComponent:
            self.editorComponent.requestFocus() # explanation below
            self.editorComponent.selectAll()
            if isinstance( event_obj, java.awt.event.MouseEvent ):
                self.cellEditor.start_editing = None
        return result

class DatesTableCellEditor( javax.swing.DefaultCellEditor ):
    def __init__( editor_self, table, *args, **kvargs ):
        jtf = javax.swing.JTextField()
        class JTFCaretListener( javax.swing.event.CaretListener ):
            def caretUpdate( self, caret_event ):
                if hasattr( editor_self, 'start_editing' ):                     
                    del editor_self.start_editing
                    if caret_event.dot == caret_event.mark and editor_self.clickCountToStart == 2:
                        caret_event.source.selectAll()
        jtf.addCaretListener( JTFCaretListener())
        javax.swing.DefaultCellEditor.__init__( editor_self, jtf, **kvargs )

在 Java 中可以实现类似的结果,显然,使用编辑器的私有字段,或类似的东西。

注意为什么我把 "requestFocus" 放在那里?如果在 editable table 单元格上按 F2 键,编辑就会开始,编辑器组件(通常是 JTextField)会自动获得焦点。但是,您也可以通过在 table 单元格中键入内容来开始编辑。我费了好大劲才弄明白,奇怪的是,如果你这样做,你确实开始编辑了,但是 editor 组件不会自动获得焦点。所以这是 "resolve this anomaly".

的一种方式

NB2 关于我的解决方案的最后一点。在现实世界的实现中,您还需要设置一个计时器,以便在一定的有限时间(例如 0.5 秒)后删除属性 "start_editing"。否则您可能会单击一次,这不会启动编辑会话(如果单击开始 == 2),然后在 10 秒后再次单击,在通过另一种方式开始编辑后,会发现 selectAll发生混乱和莫名其妙。此属性必须像碟中谍中的磁带一样:x 秒后自毁...