我有很多针对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;
}
I.E内部有多个组件的面板。实际的文本编辑器是作为编辑器返回的组件的后代。
因此,除了我所知道的问题之外,JTable正在关注getTableCellEditorComponent
方法返回的组件,因此当您按下一个突出显示单元格的键时,它会将焦点和按键移动到面板上,认为这是编辑。
无论如何我可以通知JTable“真正的”编辑器是JTextfield吗?
在正确的组件上添加hacky requestFocusInWindow
是不够的,因为按键不会被传递。
答案 0 :(得分:4)
关于JTable编辑的另一个good article。
答案 1 :(得分: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诗歌的某个地方,但它应该可以解决你眼前的问题。
答案 2 :(得分: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,并确保将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();
答案 3 :(得分: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作为编辑器。)
答案 4 :(得分:0)
我有类似的问题。在我的情况下,我有复杂的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) {
}
}