2013-12-07 9 views
0

Здесь находится SSCCE JTextField, который автоматически заполняет JTable.Обновление JTable после выбора строки

Он отлично работает, пока я не захотел что-то сделать, когда выбрана строка. Проблема заключается в том, что всякий раз, когда выбрана строка в JTable, изменяя JTextField текст бросает исключение:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1 
    at java.util.Vector.elementAt(Vector.java:430) 
    at javax.swing.table.DefaultTableModel.getValueAt(DefaultTableModel.java:632) 
    at javax.swing.JTable.getValueAt(JTable.java:2681) 
    at fr.ensicaen.si.client.AnimalAutoComplete$1.valueChanged(AnimalAutoComplete.java:73) 
    at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:167) 
    at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:147) 
    at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:194) 
    at javax.swing.DefaultListSelectionModel.changeSelection(DefaultListSelectionModel.java:388) 
    at javax.swing.DefaultListSelectionModel.changeSelection(DefaultListSelectionModel.java:398) 
    at javax.swing.DefaultListSelectionModel.removeSelectionIntervalImpl(DefaultListSelectionModel.java:559) 
    at javax.swing.DefaultListSelectionModel.clearSelection(DefaultListSelectionModel.java:403) 
    at javax.swing.JTable.clearSelection(JTable.java:2075) 
    at fr.ensicaen.si.client.AnimalAutoComplete$AutoCompleteListener.fill(AnimalAutoComplete.java:97) 
    at fr.ensicaen.si.client.AnimalAutoComplete$AutoCompleteListener.insertUpdate(AnimalAutoComplete.java:93) 

На самом деле, выбор строки и сделать что-то работает. Но когда изменен JTextField, ListSelectionListener уволен снова (но не должен?), И я не могу понять, почему!

import java.awt.BorderLayout; 
import java.awt.EventQueue; 
import java.util.ArrayList; 
import java.util.List; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.JTextField; 
import javax.swing.border.EmptyBorder; 
import javax.swing.event.DocumentEvent; 
import javax.swing.event.DocumentListener; 
import javax.swing.event.ListSelectionEvent; 
import javax.swing.event.ListSelectionListener; 
import javax.swing.table.DefaultTableModel; 

import java.awt.GridLayout; 

public class AnimalAutoComplete extends JFrame { 

    private JPanel contentPane; 
    private JScrollPane animalPane; 
    private JTable animalTable; 
    private JPanel panel; 
    private JTextField animalField; 

    /** Create the frame. */ 
    public AnimalAutoComplete() { 
     /* Frame structure */ 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setBounds(100, 100, 710, 471); 
     contentPane = new JPanel(); 
     contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); 
     contentPane.setLayout(new BorderLayout(0, 0)); 
     setContentPane(contentPane); 
     animalPane = new JScrollPane(); 
     contentPane.add(animalPane, BorderLayout.CENTER); 
     panel = new JPanel(); 
     contentPane.add(panel, BorderLayout.NORTH); 
     panel.setLayout(new GridLayout(1, 0, 0, 0)); 

     /* JTable model */ 
     DefaultTableModel animalModel = new DefaultTableModel(); 
     animalTable = new JTable(animalModel); 
     animalPane.setViewportView(animalTable); 
     animalModel.addColumn("Animal"); 

     /* Initially fills the JTable */ 
     List<String> animals = new ArrayList<String>(); 
     animals.add("Dog"); 
     animals.add("Cat"); 
     animals.add("Fish"); 

     for (String a : animals) { 
      animalModel.addRow(new Object[] {a}); 
     } 

     /* Text fields */ 
     animalField = new JTextField(); 
     panel.add(animalField); 
     animalField.setColumns(10); 

     /* This listener updates the JTable depending on the JTextField */ 
     animalField.getDocument().addDocumentListener(new AutoCompleteListener(animalTable, animals, animalField)); 

     /* This listener will do something useful when an animal is selected*/ 
     animalTable.getSelectionModel().addListSelectionListener(
      new ListSelectionListener(){ 
       public void valueChanged(ListSelectionEvent event) { 
        System.out.println(animalTable.getValueAt(animalTable.getSelectedRow(), 0)); 
       } 
      } 
     ); 

    } 

    private final class AutoCompleteListener implements DocumentListener { 
     private final JTable animalTable; 
     private final List<String> animals; 
     private JTextField searchedAnimal; 

     private AutoCompleteListener(JTable animalTable, 
       List<String> animals, JTextField textAnimal) { 
      this.animalTable= animalTable; 
      this.animals = animals; 
      this.searchedAnimal = textAnimal; 
     } 

     public void changedUpdate(DocumentEvent arg0) {fill();} 
     public void insertUpdate(DocumentEvent arg0) {fill();} 
     public void removeUpdate(DocumentEvent arg0) {fill();} 

     public void fill() { 
      animalTable.clearSelection(); 
      DefaultTableModel model = (DefaultTableModel) animalTable.getModel(); 
      model.setRowCount(0); 
      for (String a : animals) { 
       if (a.startsWith(this.searchedAnimal.getText())) { 
        model.addRow(new Object[] {a}); 
       } 
      } 
     } 
    } 

    public static void main(String[] args) { 
     AnimalAutoComplete frame = new AnimalAutoComplete(); 
     frame.setVisible(true); 
    } 
} 

ответ

1

Проблема заключается в том, что событие выбора запускается дважды, когда выбирается строка таблицы (или col/cell). Первый раз с индексом -1 и во второй раз с правильным индексом. Поэтому проверить с условием, если animalTable.getSelectedRow() возвращается -1:

 public void valueChanged(ListSelectionEvent event) { 
      int selRow = animalTable.getSelectedRow() 
      if(selRow >= 0) 
      { 
       System.out.println(animalTable.getValueAt(selRow, 0)); 
       // or do other things 
      } 
     } 

Как @camickr предложил ниже, вы можете также использовать event.getValueIsAdjusting() метод, который возвращает: true если выбор все еще меняется. Многие слушатели выбора списка интересуются только конечным состоянием выбора и могут игнорировать события выбора списка, когда этот метод возвращает true. Фактически использование этой функции предпочтительнее, чем упомянутая выше, поскольку она делает код действия более конкретным.

+1

Не уверен, что вы хотите проверить положительные значения. Выбор может меняться от 1 до 2. Ознакомьтесь с разделом из учебника Swing в разделе [Как написать прослушиватель списка List] (http://docs.oracle.com/javase/tutorial/uiswing/events/listselectionlistener.html) , Я думаю, вы хотите использовать метод getValueIsAdjusting() ', чтобы определить, когда выбор будет закончен. – camickr

+0

@camickr, я действительно играл когда-нибудь с прослушивателем. И вы, очевидно, правы в использовании 'getValueIsAdjusting()'. Тем не менее, причина, по которой он держит меня подальше от индекса, используя первый индекс и последний индекс и используя их для поиска выбранной ячейки (а не только строки). Я не знаю, почему у них нет такого слушателя для 'table', или я чего-то не хватает. – Sage

+0

Я не предлагаю использовать первый или последний индекс из события. Вы все равно должны получить выбранную строку из таблицы. Я просто предлагаю игнорировать события, которые генерируются, когда getValueIsAdjusted() истинно. – camickr

Смежные вопросы