JTable与复杂的编辑器

我有很多针对JTable的自定义编辑器,并且认为可用性,特别是关于使用键盘编辑的可用性是缺乏的,这是轻描淡写的。

这样做的主要原因是我的编辑器总是创建一个类似的(虽然通常更复杂)的情况:

@Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { JPanel container = new JPanel(); container.setLayout(new BorderLayout()); container.add(field, BorderLayout.CENTER); field.setText((String) value); container.add(new JButton("..."), BorderLayout.EAST); return container; } 

IE是一个内部有多个组件的面板。 实际的文本编辑器是作为编辑器返回的组件的后代。 所以,从我所知的问题来看,除了渲染问题之外,JTable正在关注getTableCellEditorComponent方法返回的组件,因此当你按下一个突出显示单元格的键时,它会将焦点和按键按下到面板,认为是编辑器。
无论如何我可以通知JTable“真正的”编辑器是JTextfield吗? 在正确的组件上添加hacky requestFocusInWindow是不够的,因为按键不会被传递。

在这里和这里查看一些相关的文章。

关于JTable编辑的另一篇好文章 。

如果我正确地阅读了您的问题,您希望用户能够立即键入单元格,而无需首先激活单元格编辑器,即,您希望激活单元格的任何键击是输入文本字段的第一个字符。

我的第一次尝试是在KeyboardFocusManager的focusOwner属性上添加propertyChangeListener,只是为了注意焦点永远不会离开JTable。 你可能也遇到过这种情况。 计划时间B.

我通过向表中添加KeyListener来实现“第一次按键”工作,该表记录了实例字段中keyPressed()方法的最后一个KeyEvent。 getTableCellEditorComponent()方法从那里读取字符。 如果用户要在第一个字符后继续键入任何字符,我还需要那个hacky requestFocusInWindow()调用。

对于我的示例应用程序,我创建了一个JTable的子类,它将KeyListener添加到自身。 让你的CellEditor实例实现KeyListener并将其添加到常规JTable是一个更好的主意,但我会留给你。

这是我修改它的代码片段:

 @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { JPanel container = new JPanel(); container.setLayout(new BorderLayout()); container.add(field, BorderLayout.CENTER); // Will want to add an instanceof check as well as a check on Character.isLetterOrDigit(char). char keypressed = ((StickyKeypressTable)table).getLastKeyPressed(); field.setText(String.valueOf(keypressed)); container.add(new JButton("..."), BorderLayout.EAST); SwingUtilities.invokeLater(new Runnable() { public void run() { // This needs to be in an invokeLater() to work properly field.requestFocusInWindow(); } }); return container; } 

至于肮脏的情况,这就在Vogon诗歌的某个地方,但它应该解决你的直接问题。

我通过两个步骤修复了类似的东西

首先从JTable覆盖editCellAt并在准备编辑器后调用requestFocus:

 public boolean editCellAt( int row, int column, EventObject e ) { if ( cellEditor != null && !cellEditor.stopCellEditing() ) { return false; } if ( row < 0 || row >= getRowCount() || column < 0 || column >= getColumnCount() ) { return false; } if ( !isCellEditable(row, column) ) return false; TableCellEditor editor=getCellEditor(row, column); if ( editor != null && editor.isCellEditable(e) ) { editorComp=prepareEditor(editor, row, column); if ( editorComp == null ) { removeEditor(); return false; } //aangepast Rectangle rect=getCellRect(row, column, false); if ( datamodel_.useAdaptedEditorRect() ) rect=datamodel_.changeRectangle(rect, editorComp); editorComp.setBounds(rect); add(editorComp); editorComp.validate(); setCellEditor(editor); setEditingRow(row); setEditingColumn(column); editor.addCellEditorListener(this); //NEXT LINE ADDED editorComp.requestFocus(); return true; } return false; } 

然后从JPanel重载requestFocus,并确保将textfield放入editorComponent:

 public class EditorPanel extends JPanel { JComponent editorComponent; public boolean isRequestFocusEnabled() { return true; } public void requestFocus() { editorComponent.requestFocus(); } } 

您始终可以获取keyEvent并自行设置:

 AWTEvent event = EventQueue.getCurrentEvent(); if ( event instanceof KeyEvent ) { char newSelection = ( (KeyEvent) event).getKeyChar(); int keyCode = ( (KeyEvent) event ).getKeyCode(); editorComponent.requestFocus(); if ( editorComponent instanceof JTextField ) { if ( ( newSelection >= (char) FIRST_ALLOWED_CHAR ) && ( newSelection != (char) LAST_ALLOWED_CHAR ) ) //comes from DefaultKeyTypedAction ( (JTextField) editorComponent ).setText(Character.toString(newSelection)); if ( keyCode == KeyEvent.VK_BACK_SPACE || keyCode == KeyEvent.VK_DELETE ) ( (JTextField) editorComponent ).setText(""); } } else editorComponent.requestFocus(); 

我想我解决了。
说实话,我不知道是什么解决了这个问题,因为我使用的是自定义编辑器,自定义渲染器和东西……

当一个单元格突出显示并按下“abc”时,屏幕上会显示3个字母(在本例中为单元格)。

 grid.addKeyListener(new KeyAdapter() { public void keyTyped(KeyEvent ke) { int l = grid.getSelectedRow(); int c = grid.getSelectedColumn(); grid.editCellAt(l, c); } }); 

嗯……我试过…… =)
(我不知道它是否相同,因为我的JTable使用JTextField和JComboBox作为编辑器)。

我有类似的问题。 在我的例子中,我有一个复杂的TableCellEditor ,它由JSpinner和其他一些组件组成。 问题是,当单元格编辑器启动时,我想将焦点转移到其内部组件。 我通过调用panel.transferFocusDownCycle()解决这个问题,但这又导致键盘事件停止工作 – 当我的内部组件有焦点并按下键时,我期望该组件将拦截此事件并更改其值。 相反,表将行焦点更改为上面的一个…我通过添加KeyListener并将所有键事件直接分派到内部组件来修复此问题。

这是基于我写的JPanel包装类,使我的生活更轻松。

 public class ContainerPanel extends JPanel implements KeyListener, FocusListener { private JComponent component = null; public ContainerPanel(JComponent component) { this.component = component; addKeyListener(this); addFocusListener(this); setFocusCycleRoot(true); setFocusTraversalPolicy(new ContainerOrderFocusTraversalPolicy()); add(component); } @Override public void keyTyped(KeyEvent e) { component.dispatchEvent(e); } @Override public void keyPressed(KeyEvent e) { component.dispatchEvent(e); } @Override public void keyReleased(KeyEvent e) { component.dispatchEvent(e); } @Override public void focusGained(FocusEvent e) { component.transferFocusDownCycle(); } @Override public void focusLost(FocusEvent e) { } }