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;
}
т. е. панель с более чем одним компонентом внутри. Фактический текстовый редактор является потомком компонента, возвращаемого в качестве редактора.
Итак, проблемы рендеринга помимо того, что я могу сказать, JTable фокусирует компонент, который возвращается getTableCellEditorComponent
метод поэтому, когда вы нажимаете клавишу с выделенной ячейкой, она передает Фокус и клавишу на панель, думая, что это редактор.
В любом случае, я могу сообщить JTable, что "реальным" редактором является JTextfield?
Добавление hacky requestFocusInWindow
на правильном компоненте недостаточно, так как нажатие клавиши не будет передано.
5 ответов
проверьте некоторые связанные статьи здесь и здесь.
другое хорошая статья о редактировании JTable в целом.
Если я правильно прочитал Ваш вопрос, вы хотите, чтобы пользователь мог сразу ввести в ячейку, не активируя сначала редактор ячеек, т. е. вы хотите, чтобы любое нажатие клавиши активировало ячейку как первый символ, введенный в текстовое поле.
моей первой попыткой было добавить propertyChangeListener в свойство focusOwner KeyboardFocusManager, только чтобы заметить, что фокус никогда не покидает JTable. Возможно, вы и с этим столкнулись. Время для плана Б.
Я получил это "первое нажатие клавиши", добавив KeyListener в таблицу, которая записывает последний KeyEvent для метода keyPressed() в поле экземпляра. Метод 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;
}
что касается гадости, это сидит где-то там с Вогонской поэзией, но это должно решить вашу непосредственную проблему.
я исправил что-то подобное в 2 шага
сначала переопределите editCellAt из JTable и вызовите 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;
}
затем перегрузите requestFocus из JPanel и убедитесь, что ваше текстовое поле помещено как 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) {
}
}