0

У меня возникают проблемы с обработчиком выбора для JTable.При выборе строки 0 в JTable обработчик выбора сходит с ума

Таблица обновляется каждые 15 секунд с обновленной нити в элементе управления.

Я хочу выбрать строку в своем JTable и извлечь содержимое столбца, которое я буду использовать для создания имени файла.

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

Я - новичок в Java, и это на грани моих знаний, поэтому мне сложно определить, что не так с кодом. Я чувствую, что у меня есть что-то делать со мной, пытаясь достичь структуры MVC, и я не могу правильно отделить код.

// Контроллер

// Appserver worker 
class AppserverWorker extends SwingWorker<Integer, Integer>{ 
    protected Integer doInBackground() throws Exception{ 

     // Check appservers 
     while(true){ 
      theModel.readAppservData(); 

      // Update action buttons 
      try { 
       if(!theModel.isStatusOk()){ 
        theGui.actionButtonPanel.setAppServBtnColor("RED"); 
        //    theGui.actionButtonPanel.setButtonFlashOn(); 
       }else theGui.actionButtonPanel.setAppServBtnColor("GREEN"); 
      } catch (IllegalArgumentException e1) { 
       sysLogger.logMsg("SEVERE",e1.getMessage()); 
       JOptionPane.showMessageDialog(null, e1.getMessage()); 
      } 

      // Update GUI 
      theGui.extAppServPanel.setAppserverData(theModel.getAppservData()); 

      // Sleep refresh time 
      // TODO read refresh from init table 
      try { 
       Thread.sleep(appServRefreshTime); 
      } catch (InterruptedException e) {} 
     } 
    } 

// List selection handler 
class SharedListSelectionHandler implements ListSelectionListener { 
    public void valueChanged(ListSelectionEvent e) { 
     if (!e.getValueIsAdjusting()){     // To avoid double trigger of listener 
      System.out.println(">>>>>>>>> Selection list handler >>>>>>>>"); 
      String fileName = null; 
      String fileExt = ".txt"; 
      ListSelectionModel lsm = (ListSelectionModel)e.getSource(); 
      try {  
       int selectedRow = lsm.getAnchorSelectionIndex();        // Get the row clicked 
       if (selectedRow>=0){               // If -1 no row selected 
        fileName = theGui.extAppServPanel.getAppservName(selectedRow)+fileExt;  // Get appserver name and build file name 
        theModel.readCollectFile(InitParameters.collectFilePath, fileName);   // Read collect file 
        theGui.extAppServPanel.setAppservInfo(theModel.getCollectFileContent()); // Fill the text panel with collect file 
       } 
      } 
      catch(FileNotFoundException e1){ 
       sysLogger.logMsg("SEVERE",this.getClass().getSimpleName()+": Collect file "+fileName+" is missing"); 
       JOptionPane.showMessageDialog(null, "Collect file "+fileName+" is missing"); 
      } 

      catch(IOException e1){ 
       sysLogger.logMsg("SEVERE",this.getClass().getSimpleName()+": System error: An I/O error occurred"); 
       System.err.println("System error: An I/O error occurred"); 
       System.exit(0);; 
      } 
     } 
    } 
} 

// Вид

public class ExtAppServPanel extends JPanel { 

private JTable table; 
private DefaultTableModel model; 

private JTextArea textAreaInfo; 
private JButton btnSaveInfo; 
private List colData; 

public boolean ignoreTableChanges = false; 

/** 
* Constructor 
*/ 
public ExtAppServPanel() { 
    System.out.println(this.getClass().getSimpleName()+": Constructor"); 

    setLayout(new MigLayout("", "[350:376.00,grow,leading]", "[100px:100,grow][][48.00,grow][]")); 
    this.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Application servers info", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0))); 

    // Set up table 
    String[] columnNames = {"Server name", "Type","Status"}; 
    model = new DefaultTableModel(null,columnNames); 
    table = new JTable(model){ 

     // Color code rows 
     @Override 
     public Component prepareRenderer(TableCellRenderer renderer, int row, int col) { 
      Component comp = super.prepareRenderer(renderer, row, col); 

      if (!isRowSelected(row)){ 
       comp.setBackground(getBackground()); 
       int modelRow = convertRowIndexToModel(row); 
       String type = (String)getModel().getValueAt(modelRow, 2); 
       if ("FAIL".equals(type)) comp.setBackground(Color.RED); 
       if ("WARNING".equals(type)) comp.setBackground(Color.YELLOW); 
      } 
      return comp; 
     } 
    }; 

    // Set grid 
    table.setGridColor(Color.LIGHT_GRAY); 

    // Set width and alignment 
    table.getColumnModel().getColumn(1).setMinWidth(200); 
    table.getColumnModel().getColumn(1).setMaxWidth(200); 
    table.getColumnModel().getColumn(1).setPreferredWidth(200); 

    table.getColumnModel().getColumn(2).setMinWidth(75); 
    table.getColumnModel().getColumn(2).setMaxWidth(75); 
    table.getColumnModel().getColumn(2).setPreferredWidth(75); 


    // Add scrollpane 
    JScrollPane scrollPane = new JScrollPane(table); 
    scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 
    scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); 
    table.setFillsViewportHeight(true); 
    this.add(scrollPane, "cell 0 0,grow"); 

    // Set up text area 
    JLabel lblDetails = new JLabel("Details"); 
    this.add(lblDetails, "cell 0 1,alignx leading"); 

    textAreaInfo = new JTextArea(); 
    textAreaInfo.setBackground(Color.BLACK); 
    textAreaInfo.setForeground(Color.GREEN); 
    textAreaInfo.setEditable(false); 
    textAreaInfo.setFont(new Font("Lucida Console",Font.PLAIN,10)); 

    JScrollPane scrollPane_1 = new JScrollPane(); 
    scrollPane_1.setViewportView(textAreaInfo); 
    this.add(scrollPane_1, "cell 0 2,grow"); 

    // Save button 
    btnSaveInfo = new JButton("Save"); 
    add(btnSaveInfo, "cell 0 3,alignx right"); 
} 

/* 
* Setters and getters 
*/ 
public void setAppserverData(ArrayList<ArrayList<String>> dataRecord) { 
    ArrayList<String> dataCol = new ArrayList<String>(); 

    // Init values array from result set 
    try { 
     model.setRowCount(0); // <<<<<<<<<< Problem 
     String[] arrayRow; 
     String status = "Ok"; 

     // Get first row from list 
     dataCol = dataRecord.get(0);      
     arrayRow = new String[dataCol.size()]; 
     arrayRow[0] = dataCol.get(2); 
     arrayRow[1] = dataCol.get(1); 
     arrayRow[2] = dataCol.get(4); 

     for (int i = 0; i < dataRecord.size(); i++){ 
      dataCol = dataRecord.get(i); 

      // Check status 
      if (dataCol.get(4).toUpperCase().equals("FAIL")){ 
       status = "FAIL"; 
      }else if (dataCol.get(4).toUpperCase().equals("WARNING")){ 
       status = "WARNING"; 
      } 

      if (!dataCol.get(2).toUpperCase().equals(arrayRow[0].toUpperCase())){ 
       arrayRow[2] = status;       // Override status 
       System.out.println(">>>>>>>>> Updating table >>>>>>>>"); 
       model.addRow(arrayRow);       // Add row to table 
       arrayRow = new String[dataCol.size()]; 
       arrayRow[0] = dataCol.get(2); 
       arrayRow[1] = dataCol.get(1); 
       arrayRow[2] = dataCol.get(4); 
       status = "Ok"; 
      } 
     } 
     setAppservName(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

// Get row count 
public int getRowCount(){ 
    return model.getRowCount(); 
} 

// Set table data 
public void setAppservName(){ 
    Vector data = model.getDataVector(); 
    Vector row = (Vector) data.elementAt(1); 

    // Copy the first column 
    int mColIndex = 0;- 
    colData = new ArrayList(table.getRowCount()+1); 

    for (int i = 0; i < table.getRowCount(); i++) { 
     row = (Vector) data.elementAt(i); 
     colData.add(row.get(mColIndex)); 
    } 
} 

// Get table data 
public String getAppservName(int rowNum){ 
    return (String) colData.get(rowNum); 
} 

// Set appserver info 
public void setAppservInfo(String appservInfo){ 
    textAreaInfo.setText(appservInfo); 
    textAreaInfo.setCaretPosition(0);  // Set cursor at top of text 
} 

// Get appserver info 
public String getAppservInfo(){ 
    return textAreaInfo.getText(); 
} 

/** 
* Action listeners 
*/ 

public void addTableRowListener(ListSelectionListener listSelectionEvent) { 
    table.getSelectionModel().addListSelectionListener(listSelectionEvent); 
} 

public void addButtonListener(ActionListener buttonEvent) { 
    btnSaveInfo.addActionListener(buttonEvent); 
    btnSaveInfo.setActionCommand("saveAppServInfo"); 
} 

}

выход трассировки при выборе ненулевой строки и обновления нить запустить

** Appserver worker ** 
CmtModel: readAppservData 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>> Rowcount = 8 

выхода трассировки при выборе нулевой строки и обновление нити запустить

** Appserver worker ** 
CmtModel: readAppservData 
>>>>>>>>> Selection list handler ! >>>>>>>> 
>> Controll: selectedRow = 0 << 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Selection list handler ! >>>>>>>> 
>> Controll: selectedRow = 1 << 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Selection list handler ! >>>>>>>> 
>> Controll: selectedRow = 2 << 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Selection list handler ! >>>>>>>> 
>> Controll: selectedRow = 3 << 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Selection list handler ! >>>>>>>> 
>> Controll: selectedRow = 4 << 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Selection list handler ! >>>>>>>> 
>> Controll: selectedRow = 5 << 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Selection list handler ! >>>>>>>> 
>> Controll: selectedRow = 6 << 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Selection list handler ! >>>>>>>> 
>> Controll: selectedRow = 7 << 
>>>>>>>>> Updating the table >>>>>>>> 
>>>>>>>>> Selection list handler ! >>>>>>>> 
>> Controll: selectedRow = 8 << 
java.lang.IndexOutOfBoundsException: Index: 8, Size: 8 
    at java.util.ArrayList.rangeCheck(Unknown Source) 
    at java.util.ArrayList.get(Unknown Source) 
    at panels.ExtAppServPanel.getAppservName(ExtAppServPanel.java:219) 
    at Control$SharedListSelectionHandler.valueChanged(Control.java:330) 
    at javax.swing.DefaultListSelectionModel.fireValueChanged(Unknown Source) 
    at javax.swing.DefaultListSelectionModel.fireValueChanged(Unknown Source) 
    at javax.swing.DefaultListSelectionModel.fireValueChanged(Unknown Source) 
    at javax.swing.DefaultListSelectionModel.insertIndexInterval(Unknown Source) 
    at javax.swing.JTable.tableRowsInserted(Unknown Source) 
    at javax.swing.JTable.tableChanged(Unknown Source) 
    at javax.swing.table.AbstractTableModel.fireTableChanged(Unknown Source) 
    at javax.swing.table.AbstractTableModel.fireTableRowsInserted(Unknown Source) 
    at javax.swing.table.DefaultTableModel.insertRow(Unknown Source) 
    at javax.swing.table.DefaultTableModel.addRow(Unknown Source) 
    at javax.swing.table.DefaultTableModel.addRow(Unknown Source) 
    at panels.ExtAppServPanel.setAppserverData(ExtAppServPanel.java:172) 
    at Control$AppserverWorker.doInBackground(Control.java:434) 
    at Control$AppserverWorker.doInBackground(Control.java:1) 
    at javax.swing.SwingWorker$1.call(Unknown Source) 
    at java.util.concurrent.FutureTask.run(Unknown Source) 
    at javax.swing.SwingWorker.run(Unknown Source) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) 
    at java.lang.Thread.run(Unknown Source) 
+0

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

+0

Очевидно, что мне приходится копать глубже в обработке потоков, но как насчет обновления таблицы? – Magher

+0

Ваш 'SwingWorker' должен использовать функцию' publish'/'process' для отправки обновлений в пользовательский интерфейс. То, что вы отправляете, будет зависеть от того, как вы хотите его достичь. Познакомьтесь с [Worker Threads and SwingWorker] (http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html) для получения более подробной информации. – MadProgrammer

ответ

2
// Update GUI 
theGui.extAppServPanel.setAppserverData(theModel.getAppservData()); 

Не обновлять модель или графический интерфейс пользователя в методе doInBackground().

Все обновления GUI должны быть выполнены на EventDispatchThread (EDT).

Вместо этого при изменении данных вам необходимо «опубликовать» результаты, чтобы код мог быть выполнен в методе process(...)SwingWorker, который выполняет на EDT, и поэтому графический интерфейс будет обновляться по EDT.

Для получения дополнительной информации ознакомьтесь с разделом из учебника Swing по телефону Concurrency. В примере на Tasks That Have Intermediate Results приведен пример подхода публикации.