JTable со сложным редактором - PullRequest
8 голосов
/ 19 февраля 2009

У меня есть много пользовательских редакторов для 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 к нужному компоненту недостаточно, так как нажатие клавиши не будет передано.

Ответы [ 5 ]

4 голосов
/ 23 февраля 2009

Проверьте некоторые похожие статьи здесь и здесь .

Еще одна хорошая статья о редактировании JTable в целом.

2 голосов
/ 19 февраля 2009

Если я правильно прочитал ваш вопрос, вы хотите, чтобы пользователь мог сразу ввести текст в ячейку, не активируя сначала редактор ячейки, т. Е. Вы хотите, чтобы любое нажатие клавиши, активировавшее ячейку, было первым символом, введенным в текстовое поле .

Моей первой попыткой было добавить propertyChangeListener в свойство focusOwner KeyboardFocusManager, только чтобы заметить, что фокус никогда не покидает JTable. Вы, вероятно, столкнулись с этим также. Время для плана Б.

Я получил эту «первую нажатие клавиши», добавив KeyListener в таблицу, которая записывает последнее KeyEvent для метода keyPressed () в поле экземпляра. Метод getTableCellEditorComponent () читает символ оттуда. Мне также нужно было, чтобы хакерский метод 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;
}

Что касается мерзости, то она сидит где-то там с Вогон Поэзией, но это должно решить вашу непосредственную проблему.

0 голосов
/ 16 ноября 2012

У меня была очень похожая проблема. В моем случае у меня был комплекс 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) {
    }
}
0 голосов
/ 04 марта 2009

Я думаю, что решил это.
Честно говоря, я не знаю, что решило проблему, так как я использую собственный редактор, пользовательский рендер и прочее ...

Когда ячейка подсвечивается и я нажимаю «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 в качестве редакторов).

0 голосов
/ 20 февраля 2009

Я исправил нечто подобное в 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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...