Java 为什么F6(或Ctrl-F6)开始编辑JTable?

Java 为什么F6(或Ctrl-F6)开始编辑JTable?,java,swing,jtable,key-bindings,Java,Swing,Jtable,Key Bindings,我想使用Ctrl-F6在JTable和关联的JTree之间切换。但是,Ctrl-F6会启动JTable的单元格编辑器。JTable只有一个默认键侦听器:javax.swing.ToolTimManager$AccessibilityKeyListener。。。但是移除这个并不能解决问题。 所以我试图找出这是否是一个键绑定,以及它可能驻留在哪里。。。因此,我编写了这个简单的函数(用Jython编写,但Java开发者应该可以完全理解): JTable的结果如下: === comp: date_tab

我想使用Ctrl-F6在JTable和关联的JTree之间切换。但是,Ctrl-F6会启动JTable的单元格编辑器。JTable只有一个默认键侦听器:javax.swing.ToolTimManager$AccessibilityKeyListener。。。但是移除这个并不能解决问题。 所以我试图找出这是否是一个键绑定,以及它可能驻留在哪里。。。因此,我编写了这个简单的函数(用Jython编写,但Java开发者应该可以完全理解):

JTable的结果如下:

=== comp: date_table
  === condition: focused
    === imap javax.swing.InputMap@1a8a84f:
  === condition: ancestor
    === imap javax.swing.InputMap@1c1edd9:
      === imap javax.swing.plaf.InputMapUIResource@e674b9:
        === keystroke ctrl pressed DOWN value selectNextRowChangeLead
        === keystroke shift pressed UP value selectPreviousRowExtendSelection
        === keystroke shift pressed INSERT value paste
        === keystroke ctrl pressed RIGHT value selectNextColumnChangeLead
        === keystroke shift ctrl pressed LEFT value selectPreviousColumnExtendSe
lection
        === keystroke shift pressed KP_UP value selectPreviousRowExtendSelection
        === keystroke pressed DOWN value selectNextRow
        === keystroke ctrl pressed UP value selectPreviousRowChangeLead
        === keystroke ctrl pressed LEFT value selectPreviousColumnChangeLead
        === keystroke pressed CUT value cut
        === keystroke pressed END value selectLastColumn
        === keystroke shift pressed PAGE_UP value scrollUpExtendSelection
        === keystroke pressed KP_UP value selectPreviousRow
        === keystroke shift ctrl pressed UP value selectPreviousRowExtendSelecti
on
        === keystroke ctrl pressed HOME value selectFirstRow
        === keystroke ctrl pressed INSERT value copy
        === keystroke shift pressed LEFT value selectPreviousColumnExtendSelecti
on
        === keystroke ctrl pressed END value selectLastRow
        === keystroke ctrl pressed PAGE_DOWN value scrollRightChangeSelection
        === keystroke shift ctrl pressed RIGHT value selectNextColumnExtendSelec
tion
        === keystroke pressed LEFT value selectPreviousColumn
        === keystroke ctrl pressed PAGE_UP value scrollLeftChangeSelection
        === keystroke pressed KP_LEFT value selectPreviousColumn
        === keystroke shift pressed KP_RIGHT value selectNextColumnExtendSelecti
on
        === keystroke pressed SPACE value addToSelection
        === keystroke ctrl pressed SPACE value toggleAndAnchor
        === keystroke shift pressed SPACE value extendTo
        === keystroke shift ctrl pressed SPACE value moveSelectionTo
        === keystroke shift ctrl pressed DOWN value selectNextRowExtendSelection
        === keystroke ctrl pressed BACK_SLASH value clearSelection
        === keystroke pressed ESCAPE value cancel
        === keystroke shift pressed DELETE value cut
        === keystroke shift pressed HOME value selectFirstColumnExtendSelection
        === keystroke pressed ENTER value selectNextRowCell
        === keystroke shift pressed ENTER value selectPreviousRowCell
        === keystroke pressed F8 value focusHeader
        === keystroke pressed RIGHT value selectNextColumn
        === keystroke shift ctrl pressed PAGE_UP value scrollLeftExtendSelection
        === keystroke shift pressed DOWN value selectNextRowExtendSelection
        === keystroke shift ctrl pressed KP_UP value selectPreviousRowExtendSele
ction
        === keystroke pressed PAGE_DOWN value scrollDownChangeSelection
        === keystroke shift pressed KP_LEFT value selectPreviousColumnExtendSele
ction
        === keystroke ctrl pressed X value cut
        === keystroke shift ctrl pressed PAGE_DOWN value scrollRightExtendSelect
ion
        === keystroke ctrl pressed SLASH value selectAll
        === keystroke ctrl pressed C value copy
        === keystroke ctrl pressed KP_RIGHT value selectNextColumnChangeLead
        === keystroke shift pressed END value selectLastColumnExtendSelection
        === keystroke shift ctrl pressed KP_DOWN value selectNextRowExtendSelect
ion
        === keystroke shift pressed TAB value selectPreviousColumnCell
        === keystroke ctrl pressed KP_LEFT value selectPreviousColumnChangeLead
        === keystroke pressed HOME value selectFirstColumn
        === keystroke ctrl pressed V value paste
        === keystroke pressed KP_DOWN value selectNextRow
        === keystroke ctrl pressed KP_DOWN value selectNextRowChangeLead
        === keystroke shift pressed RIGHT value selectNextColumnExtendSelection
        === keystroke ctrl pressed A value selectAll
        === keystroke shift ctrl pressed END value selectLastRowExtendSelection
        === keystroke pressed COPY value copy
        === keystroke ctrl pressed KP_UP value selectPreviousRowChangeLead
        === keystroke shift ctrl pressed KP_LEFT value selectPreviousColumnExten
dSelection
        === keystroke shift pressed KP_DOWN value selectNextRowExtendSelection
        === keystroke pressed TAB value selectNextColumnCell
        === keystroke pressed UP value selectPreviousRow
        === keystroke shift ctrl pressed HOME value selectFirstRowExtendSelectio
n
        === keystroke shift pressed PAGE_DOWN value scrollDownExtendSelection
        === keystroke pressed KP_RIGHT value selectNextColumn
        === keystroke shift ctrl pressed KP_RIGHT value selectNextColumnExtendSe
lection
        === keystroke pressed F2 value startEditing
        === keystroke pressed PAGE_UP value scrollUpChangeSelection
        === keystroke pressed PASTE value paste
  === condition: in focused window
    === imap javax.swing.ComponentInputMap@fa5f28:
。。。没有任何F6或Ctrl-F6键绑定的迹象。。。有人知道发生了什么事吗

以后

顺便说一句,完全可以将Ctrl-F6绑定添加到(例如)JTable的“WHEN祖先…”InputMap(例如,第一代,即javax.swing)中。InputMap@1c1edd9在上面的列表中)。然后在那里的对象和ActionMap中的动作之间添加绑定。Ctrl-F6然后启动该操作。但是,正如人们可能预期的那样,这绝不会阻止“启动”行动。神秘的奥秘在于:费金在哪里???我已经研究了JScrollPane(没有乐趣,也没有惊喜),甚至是提交给DefaultCellEditor的构造函数的JTextField对象。。。(没有欢乐,更没有惊喜)。难倒了。有人认识超级极客吗

甚至以后

虽然Yarik已经解决了主要的问题,但我仍然有一个问题:当实现表并通过编程(即不使用鼠标)将焦点放在先前选择的行上时,F2最初不起作用。。。只有在导航(例如,使用向上/向下键)后,您才会发现F2开始编辑。SSCCE说明问题:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.lang.Runnable;
import javax.swing.*;


public class TableCellEditProb {
    public static void main(String args[]) {
        Runnable show_frame = new Runnable(){
            public void run(){
                JFrame main_frame = new JFrame( "F2 no effect on first realisation!");
                main_frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
                final JTable table = new JTable( 5, 2 );
                table.setPreferredSize( new Dimension( 400, 200 ));
                table.setRowSelectionInterval( 2, 2 );
                table.putClientProperty("JTable.autoStartsEdit", false );      
                JPanel panel = new JPanel( new BorderLayout());
                AbstractAction button_action = new AbstractAction(){
                    public void actionPerformed(ActionEvent e){
                        System.out.println( "button pressed");
                        table.requestFocus();
                    }
                };
                button_action.putValue( AbstractAction.NAME, "Click (or press spacebar) to change focus to table..." );
                JButton button = new JButton( button_action );
                panel.add( table, BorderLayout.WEST );
                panel.add( button, BorderLayout.EAST );
                main_frame.getContentPane().add( panel );
                main_frame.pack();
                button.requestFocus();
                main_frame.setVisible( true );
            }
        };
        java.awt.EventQueue.invokeLater( show_frame );
    }
}
默认操作键由InputMap和ActionMap中的L&F定义 我相信他们是在任何外部听众面前被呼叫的。 您可以随时覆盖它

或者,您可以覆盖processKeyBinding

下面是一个代码示例,它可以执行您需要的操作。 它截取Cntrl-F6并打印到sysout

关于Cntrl-F6不在绑定中的原因,请参阅我的评论

公共类打印表测试{

public JPanel buildUI() {
    String[] columnNames = {"First Name",
            "Last Name",
            "Sport",
            "# of Years",
            "Vegetarian"};

    Object[][] data = {
            {"Mary", "Campione",
                    "Snowboarding", 5, new JComboBox(new Object[]{Boolean.TRUE, Boolean.FALSE})},
            {"Alison", "Huml",
                    "Rowing", 3, Boolean.FALSE},
            {"Kathy", "Walrath",
                    "Knitting", 2, Boolean.FALSE},
            {"Sharon", "Zakhour",
                    "Speed reading", 20, Boolean.TRUE},
            {"Philip", "Milne",
                    "Pool", 10, Boolean.TRUE
            }
    };


    final JTable table = new JTable(increase(data, 50), columnNames);
    JScrollPane scrollPane = new JScrollPane(table);
    JButton print = new JButton("Print");
    print.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            try {
                table.print();
            } catch (PrinterException e1) {
                e1.printStackTrace();
            }
        }
    });

    table.setDefaultRenderer(TableColumn.class, new TableCellRenderer());
    JPanel panel = new JPanel(new BorderLayout(5, 5));
    panel.add(scrollPane, BorderLayout.CENTER);
    panel.add(print, BorderLayout.SOUTH);
    JTextField textField = new JFormattedTextField();
    JSpinner spinner = new JSpinner(new SpinnerNumberModel());
    spinner.setEditor(textField);
    textField.setEditable(false);
    panel.add(spinner, BorderLayout.NORTH);


    panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F6, InputEvent.CTRL_DOWN_MASK), "doSomething" );
    panel.getActionMap().put("doSomething",new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("TEST OUT");
        }
    });
    table.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
    return panel;
}

private Object[][] increase(Object[][] src, int times) {

    Object[][] out = new Object[src.length * times][];
    for (int i = 0; i < times; i++) {
        System.arraycopy(src, 0, out, i * src.length, src.length);
    }
    return out;
}

public JFrame getFrame(String name) {
    JFrame frame = new JFrame(name);
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.setContentPane(buildUI());
    frame.setSize(200, 200);
    frame.pack();

    return frame;

}

public static void main
        (String[] args) {
    SwingUtilities.invokeLater(new Runnable() {

        public void run() {
            PrintTableTest ui = new PrintTableTest();
            JFrame frame = ui.getFrame("TABLE PRINT TEST");
            frame.setVisible(true);
        }
    });
}

private class TableCellRenderer extends DefaultTableCellRenderer {

    /**
     * Returns the default table cell renderer.
     *
     * @param table      the <code>JTable</code>
     * @param value      the value to assign to the cell at <code>[row, column]</code>
     * @param isSelected true if cell is selected
     * @param hasFocus   true if cell has focus
     * @param row        the row of the cell to render
     * @param column     the column of the cell to render
     * @return the default table cell renderer
     */
    public Component getTableCellRendererComponent(JTable table,
                                                   Object value,
                                                   boolean isSelected,
                                                   boolean hasFocus,
                                                   int row,
                                                   int column) {
        if (value instanceof JComboBox) {
            return (Component) value;
        }
        return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

    }
}

}

如引用的关键绑定文章所示,许多L&F将
F2
绑定到
startEditing
。。。我知道F2是。。。如果您愿意查看,它将显示在输入地图的列表中!但是我的问题是关于Ctrl-F6,你有没有尝试过这个问题的解决方案:我非常关心的不仅是看,而且还引用了一篇有用的文章;不客气。我看到
com.apple.laf.AquaLookAndFeel
绑定了
F6
,也许是为了避免冲突。@trashgod thanx-我认为这是一个Windows框,特别是Windows 7。。。另外,我没有使用Apple L&F。谢谢,但是只有知道在哪里可以找到将击键绑定到对象的InputMap(对象然后绑定到ActionMap中的操作),才能覆盖某些内容。我的问题是我找不到输入映射。这也意味着我不能删除绑定。默认值应该在JTable UI委托中,因此请检查源代码。您仍然可以覆盖JTable.processKeyBundings。如果我在editCellAt()上放置一个断点,堆栈跟踪将显示路径。顺便说一句,在调试代码一段时间后,我可以看到Ctrl-F6没有任何意义。任何按下的键都会触发编辑,只是碰巧这些键不会生成可打印的字符。用F7或F8尝试相同的方法。简而言之,覆盖processKeyBinding,添加操作并添加客户机属性table.putClientProperty(“JTable.autoStartsEdit”,Boolean.FALSE);这样做的副作用是不使用任何键开始编辑-只要您可以使用它即可:-)@kleopatra F2仍然有效,因为它包含在InputMap列表中(请参见上文)。同样毫无疑问,人们可以在JTable上放置一个KeyListener,它将开始编辑所有实际打印内容的键。在我看来,这应该是autoStartsEdit=True的默认行为……除F2之外的任何键,你都是挑剔者——这通常是我的角色:-)根据设计,由编辑器决定是否要开始(或继续,fwim)对特定击键的编辑,表在其中没有太多的作用。因此,您可以尝试相应地实现它的isCellEditable(EventObject)——这不是完全不重要的,因为有几个原因(与表一样,编辑器对editingComponent的内部结构不太了解:textField没有公共api来决定给定的按键是否会产生有效的键入键)
public JPanel buildUI() {
    String[] columnNames = {"First Name",
            "Last Name",
            "Sport",
            "# of Years",
            "Vegetarian"};

    Object[][] data = {
            {"Mary", "Campione",
                    "Snowboarding", 5, new JComboBox(new Object[]{Boolean.TRUE, Boolean.FALSE})},
            {"Alison", "Huml",
                    "Rowing", 3, Boolean.FALSE},
            {"Kathy", "Walrath",
                    "Knitting", 2, Boolean.FALSE},
            {"Sharon", "Zakhour",
                    "Speed reading", 20, Boolean.TRUE},
            {"Philip", "Milne",
                    "Pool", 10, Boolean.TRUE
            }
    };


    final JTable table = new JTable(increase(data, 50), columnNames);
    JScrollPane scrollPane = new JScrollPane(table);
    JButton print = new JButton("Print");
    print.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            try {
                table.print();
            } catch (PrinterException e1) {
                e1.printStackTrace();
            }
        }
    });

    table.setDefaultRenderer(TableColumn.class, new TableCellRenderer());
    JPanel panel = new JPanel(new BorderLayout(5, 5));
    panel.add(scrollPane, BorderLayout.CENTER);
    panel.add(print, BorderLayout.SOUTH);
    JTextField textField = new JFormattedTextField();
    JSpinner spinner = new JSpinner(new SpinnerNumberModel());
    spinner.setEditor(textField);
    textField.setEditable(false);
    panel.add(spinner, BorderLayout.NORTH);


    panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F6, InputEvent.CTRL_DOWN_MASK), "doSomething" );
    panel.getActionMap().put("doSomething",new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("TEST OUT");
        }
    });
    table.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
    return panel;
}

private Object[][] increase(Object[][] src, int times) {

    Object[][] out = new Object[src.length * times][];
    for (int i = 0; i < times; i++) {
        System.arraycopy(src, 0, out, i * src.length, src.length);
    }
    return out;
}

public JFrame getFrame(String name) {
    JFrame frame = new JFrame(name);
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.setContentPane(buildUI());
    frame.setSize(200, 200);
    frame.pack();

    return frame;

}

public static void main
        (String[] args) {
    SwingUtilities.invokeLater(new Runnable() {

        public void run() {
            PrintTableTest ui = new PrintTableTest();
            JFrame frame = ui.getFrame("TABLE PRINT TEST");
            frame.setVisible(true);
        }
    });
}

private class TableCellRenderer extends DefaultTableCellRenderer {

    /**
     * Returns the default table cell renderer.
     *
     * @param table      the <code>JTable</code>
     * @param value      the value to assign to the cell at <code>[row, column]</code>
     * @param isSelected true if cell is selected
     * @param hasFocus   true if cell has focus
     * @param row        the row of the cell to render
     * @param column     the column of the cell to render
     * @return the default table cell renderer
     */
    public Component getTableCellRendererComponent(JTable table,
                                                   Object value,
                                                   boolean isSelected,
                                                   boolean hasFocus,
                                                   int row,
                                                   int column) {
        if (value instanceof JComboBox) {
            return (Component) value;
        }
        return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

    }
}