Обновление ячейки JTable не работает

В моем приложении я использую таблицу Java, которая похожа на этот пример. Моя проблема заключается в том, что когда я меняю значение ячейки (даже в приведенном выше примере), модель данных не обновляется, пока я не нажму на другую ячейку. Даже если я нажму на серую область под таблицей после изменения значения ячейки, модель не изменится. Я думаю, что причина в том, что ячейка остается сфокусированной, пока я не нажму на другую ячейку. Как этого избежать и обновить модель, не нажимая на ячейку таблицы. заранее спасибо

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

public class JTableDemo extends JApplet {
  private JTextArea txt = new JTextArea(4, 20);

  // The TableModel controls all the data:
  class DataModel extends AbstractTableModel {
    Object[][] data = { { "one", "two", "three", "four" },
        { "five", "six", "seven", "eight" },
        { "nine", "ten", "eleven", "twelve" }, };

    // Prints data when table changes:
    class TML implements TableModelListener {
      public void tableChanged(TableModelEvent e) {
        txt.setText(""); // Clear it
        for (int i = 0; i < data.length; i++) {
          for (int j = 0; j < data[0].length; j++)
            txt.append(data[i][j] + " ");
          txt.append("\n");
        }
      }
    }

    public DataModel() {
      addTableModelListener(new TML());
       fireTableDataChanged();
    }

    public int getColumnCount() {
      return data[0].length;
    }

    public int getRowCount() {
      return data.length;
    }

    public Object getValueAt(int row, int col) {
      return data[row][col];
    }

    public void setValueAt(Object val, int row, int col) {
      data[row][col] = val;
      System.out.println(val);
      // Indicate the change has happened:
      fireTableDataChanged();
    }

    public boolean isCellEditable(int row, int col) {
      return true;
    }
  }

  public void init() {
    Container cp = getContentPane();
    JTable table = new JTable(new DataModel());
    cp.add(new JScrollPane(table));
    cp.add(BorderLayout.SOUTH, txt);
  }

  public static void main(String[] args) {
    run(new JTableDemo(), 350, 200);
  }

  public static void run(JApplet applet, int width, int height) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(applet);
    frame.setSize(width, height);
    applet.init();
    applet.start();
    frame.setVisible(true);
  }
}

Когда вы запускаете пример, вы можете увидеть содержимое таблицы в текстовой области под таблицей. После обновления ячейки она должна появиться в текстовом поле ниже. Но метод setValueAt не будет вызываться, пока вы не нажмете на другую ячейку.


person nath    schedule 31.10.2011    source источник
comment
Можете ли вы отредактировать свой вопрос и добавить SSCCE, указывающий на проблему?   -  person Bart Kiers    schedule 31.10.2011


Ответы (3)


Механизм обновления по умолчанию изменяет модель только тогда, когда редактор ячеек теряет фокус. Либо выход из ячейки, либо щелчок в другой ячейке вызовет жизненно важное событие «потеря фокуса», которое запускает изменение модели.

Щелчок в серой области не имеет никакого эффекта, потому что там нет активных элементов, которые могли бы обработать событие - таблица игнорирует щелчок.

Если вы хотите изменить это, вам нужно найти событие, которое сообщает компьютеру, что пользователь "завершил редактирование". Откуда ты это знаешь?

  • Вы можете добавить ActionListener (см. http://download.oracle.com/javase/tutorial/uiswing/components/textfield.html). Он сработает, когда вы нажмете RETURN. В обработчике вызовите fireEditingStopped(), чтобы запустить код «копирования в модель» (см. http://download.oracle.com/javase/tutorial/uiswing/components/table.html#editor).
  • Вы можете добавить кнопку «Сохранить» под таблицей и вызвать этот код в ней ActionListner:

    if(null != jTable.getCellEditor()) {
        // there is an edit in progress
        jTable.getCellEditor().stopCellEditing()
    }
    
  • Вы можете обновить модель для каждого нажатия клавиши, добавив обработчик нажатия клавиши, но это может привести к исчезновению редактора.

[EDIT] Обратите внимание, что добавление кнопки "Сохранить" может нарушить "поток" редактирования пользователей (щелчок по ячейке таблицы, редактирование, захват мыши, прицеливание, щелчок "Сохранить", щелчок по следующей ячейке, возврат к клавиатуре). , редактировать, ...)

person Aaron Digulla    schedule 31.10.2011
comment
Просто добавьте кнопку, которая ничего не делает, с меткой Сохранить. Наряду со свойством клиента из ответа Клеопатры это должно помочь. Обратите внимание, что это будет сильно раздражать ваших пользователей, потому что означает дополнительный щелчок мышью. Попробуйте добавить мнемонику, чтобы люди могли прекратить редактирование с помощью Alt+S (не отходя от клавиатуры). - person Aaron Digulla; 31.10.2011
comment
no: focusLost по умолчанию не запускает фиксацию (что было давней проблемой целую вечность, пока ОНИ не смогли убедить хотя бы поддерживать опциональную установку такого поведения). На самом деле, фиксация табуляции или нажатия на другую ячейку явно запускается кодом tableUI. - person kleopatra; 31.10.2011
comment
@Kleo: Вы, вероятно, пропустили вместе со свойством клиента из ответа клеопатры. Если это не сработает, вам нужно будет вызвать fireEditingStopped() редактора ячеек в обработчике нажатия кнопки. - person Aaron Digulla; 31.10.2011
comment
Я сделал это следующим образом. Когда пользователь нажимает кнопку сохранения в списке действий сохранения, я вызываю jTable.getCellEditor().stopCellEditing(); метод. - person nath; 31.10.2011
comment
хах ... действительно, я пропустил эту строку :-) - ослепил меня - не читал комментарий) Суть, на которой я настаиваю, заключается в том, чтобы не связывать фокус и фиксировать с помощью табуляции/щелчка другого клетка, они разные звери. И нет, вы никогда не вызываете fireEditingStopped из какого-либо обработчика вне редактора (вместо этого вызываете stopCellEditing). На самом деле, никогда не вызывайте какой-либо fireXX из-за пределов класса, который его определяет... (ограничение на редактирование в пять минут заставило меня удалить старый и написать новый комментарий ;-) - person kleopatra; 31.10.2011
comment
Примечание. jTable.getCellEditor() вернет значение null, если редактирование не выполняется. - person James Wierzba; 04.05.2015

Это ожидаемое поведение: отредактированное значение не фиксируется в модели поддержки до тех пор, пока явный жест пользователя, например f.i. нажатие ввода или табуляция или щелчок в другом месте таблицы ...

Одна странность (некоторые называют это ошибкой :-) JTable заключается в том, что редактирование по умолчанию не прекращается при передаче фокуса «вне» таблицы. Чтобы заставить это сделать, вам нужно настроить его следующим образом:

  table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

Кстати (не связанно, просто для здравомыслия): всегда запускайте наиболее мелкозернистый тип события, здесь это будет cellUpdated вместо молотка dataChanged.

person kleopatra    schedule 31.10.2011
comment
Я люблю ваши понедельники, отличный и ценный ответ +1 - person mKorbel; 31.10.2011

Для моего случая

public void setValueAt(Object val, int row, int col) {
  data[row][col] = val;
  System.out.println(val);
  // Indicate the change has happened:
  fireTableDataChanged();
}

вам также нужно вызвать суперфункцию.

public void setValueAt(Object val, int row, int col) {
  data[row][col] = val;
  System.out.println(val);
  // Indicate the change has happened:
  fireTableDataChanged();
  super.setValueAt(val,row,col);
}
person Furkan Katı    schedule 14.04.2020