8

我有许多 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吗?在正确的组件上添加 hackyrequestFocusInWindow是不够的,因为按键不会被传递。

4

4 回答 4

2

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

我的第一次尝试是在 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 Poetry 位于某个地方,但它应该可以解决您的直接问题。

于 2009-02-19T19:12:52.493 回答
0

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

当一个单元格突出显示并按“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作为编辑器)。

于 2009-03-04T20:16:18.660 回答
0

我分两步修复了类似的东西

首先覆盖 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 并确保您的文本字段被放置为 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();
于 2009-02-20T08:07:17.917 回答
0

I had very similar problem. In my case I had complex TableCellEditor which consists of JSpinner and some other components. The problem was that when cell editor started I wanted to transfer focus to its internal component. I fixed this by calling panel.transferFocusDownCycle() but this in turn caused keyboard events to stop working - when my internal component had focus and I pressed key up, I was expecting that component will intercept this event and change its value. Instead table changed row focus to one above... I fixed this by adding KeyListener and dispatching all key events directly to the internal component.

This is wrapper class based on JPanel I wrote to make my life easier.

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) {
    }
}
于 2012-11-15T21:09:51.333 回答