Java 我如何模拟;onStartCellEditing";对于DefaultCellEditor

Java 我如何模拟;onStartCellEditing";对于DefaultCellEditor,java,swing,tablecelleditor,Java,Swing,Tablecelleditor,CellEditorListener有“editingStopped”和“editingCancelled”。但是,如何实现一段需要在单元格编辑会话启动时运行的代码呢 一个典型的例子可能是,当您开始编辑时,希望JTextField编辑器组件的文本转到selectAll()。我很想做的事情是重写DefaultCellEditor的一个方法,例如getTableCellEditorComponent或getCellEditorValue或getComponent,但这些方法都没有明确表示在编辑会话开

CellEditorListener有“editingStopped”和“editingCancelled”。但是,如何实现一段需要在单元格编辑会话启动时运行的代码呢

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

相反,我们知道,如果我们正在编辑,JTable.getCellEditor将返回编辑器,如果没有返回,则返回null。这是因为在开始编辑时,组件被制作成JTable的子对象。它似乎也在编辑会话开始时获得焦点,因此您可能会考虑向编辑器组件(JTextField等)添加一个FocusListener。但这能保证吗?此外,在编辑过程中,焦点可能会丢失,然后返回

有一种监听编辑器组件“添加”(作为子对象)的方法:ContainerListener。除非有人告诉我不同的情况,否则这似乎是最直接、最合理的方式来接到编辑会议已经开始的电话。但奇怪的是没有更直接的方法

一个典型的例子可能是,当您开始编辑时,希望JTextField编辑器组件的文本转到selectAll()

开始编辑后,您可以覆盖JTable的
editCellAt(…)
方法来选择文本:

@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;
}

罗布·卡米克的答案很好,但我还有另一个答案供“完美主义者”阅读

我使用Jython,但它应该足够简单,让Java人员能够理解。在Python/Jython中,您可以(几乎)向任何对象添加任意“属性”。因此,在editCellAt中,我添加了一个属性“start_editing”,然后向添加到JTextField编辑器组件的插入符号侦听器发送信号,表示会话刚刚开始。如果插入符号点和标记相等(折叠),如果单击计数开始编辑==2,并且如果编辑器具有“开始编辑”属性,则选择“全部”(再次),并删除“开始编辑”属性。。。它可以工作(!),而不会产生新的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中,使用编辑器的私有字段或类似的内容也可以获得类似的结果

NB为什么我要把“请求焦点”放在那里?如果在可编辑的表格单元格上按F2键,编辑将开始,编辑器组件(通常是JTextField)将自动获得焦点。但是,您也可以通过在表格单元格中键入来开始编辑。我费了好大劲才弄明白,奇怪的是,如果你这样做了,你确实开始编辑了,但是编辑器组件不会自动获得焦点。因此,这是一种“解决此异常”的方法


NB2关于我的解决方案的最后一点。在实际的实现中,您还需要设置一个计时器,以便在一定的有限时间(例如0.5秒)后删除属性“开始编辑”。否则,您可能会单击一次,这将不会启动编辑会话(如果单击开始==2),然后在通过其他方式开始编辑后,在10秒后再次单击,以发现selectAll的发生令人费解。必须将此属性设置为“不可能完成的任务:x秒后自毁”中的磁带…

谢谢:我不知道editCellAt在用户操作后被触发。我刚刚尝试的一个版本省略了对“e”的测试,使我的单元测试通过了。这是由KeyEvent.VK_F2上的java.awt.Robot模拟按键造成的。我将不得不做一些实验来理解产生新Runnable的绝对必要性,除非绝对没有其他方法,否则我会避免。并且确实要确定编辑器是否为空。但我知道你的代表,所以毫无疑问你可以详细说明这一点@MikCorevent,
我将要做一些实验,以了解生成新的可运行的
的绝对必要性-您可以查看。源代码中的注释解释了我添加invokeLater(…)的原因。谢谢。第二次鼠标单击,右键。我不认为invokeLater Runnable实际上可能在第二次单击之前运行?此外,我认为可能会使用DefCellEditor.getClickCountToStart()1)的设置来决定不生成(如果==1)和2)以预测和取消插入符号的折叠(如果==2)。。。只是想大声说出来,但你可能已经考虑过这些,并决定这是过度思考的问题。。。