2013-05-30 23 views
0

我有一個可排序的JTable;當添加一行時,我想知道它的視圖-index。我嘗試使用這樣的表模型監聽器:將modelRowIndex轉換爲viewRowIndex以進行排序的JTable

@Override 
public void tableChanged(TableModelEvent event) 
{ 
    if (event.getType() == TableModelEvent.INSERT) 
    { 
     int modelRowIndex = event.getFirstRow(); 
     int viewRowIndex = table.convertRowIndexToView(modelRowIndex); 
     System.out.println("viewRowIndex: " + viewRowIndex); 
    } 
} 

如果表未被排序,這將起作用。不幸的是,如果對錶格進行排序,則轉換方法導致ArrayIndexOutOfBoundsExceptionDefaultRowSorter.java:503引起。

我想這是因爲表模型在通知行分類器之前通知我的監聽器。有任何想法嗎?謝謝!

這裏是一個SSCCE:

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.ArrayList; 
import java.util.List; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.SwingUtilities; 
import javax.swing.event.TableModelEvent; 
import javax.swing.event.TableModelListener; 
import javax.swing.table.AbstractTableModel; 

public class RowIndexSSCCE extends JFrame 
{ 
    public static void main(String[] args) 
    { 
     SwingUtilities.invokeLater(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       new RowIndexSSCCE().setVisible(true); 
      } 
     }); 
    } 

    private final JTable table; 

    public RowIndexSSCCE() 
    { 
     JButton button = new JButton("Add"); 
     button.addActionListener(new ButtonListener()); 

     table = new JTable(new Model()); 
     table.setAutoCreateRowSorter(true); 
     table.getModel().addTableModelListener(new ModelListener()); 

     JScrollPane scrollPane = new JScrollPane(table); 
     JPanel panel = new JPanel(); 
     panel.add(button); 
     panel.add(scrollPane); 
     add(panel); 
     pack(); 
     setLocationRelativeTo(null); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
    } 

    private class ButtonListener implements ActionListener 
    { 
     @Override 
     public void actionPerformed(ActionEvent event) 
     { 
      ((Model) table.getModel()).addRow("asdf" + table.getRowCount()); 
     } 
    } 

    private class ModelListener implements TableModelListener 
    { 
     @Override 
     public void tableChanged(TableModelEvent event) 
     { 
      if (event.getType() == TableModelEvent.INSERT) 
      { 
       int modelRowIndex = event.getFirstRow(); 
       int viewRowIndex = table.convertRowIndexToView(modelRowIndex); 
       System.out.println("viewRowIndex: " + viewRowIndex); 
      } 
     } 
    } 

    private class Model extends AbstractTableModel 
    { 
     private final List<String> data = new ArrayList<String>(); 

     public void addRow(String string) 
     { 
      int oldSize = data.size(); 
      data.add(string); 
      fireTableRowsInserted(oldSize, oldSize); 
     } 

     @Override 
     public int getRowCount() 
     { 
      return data.size(); 
     } 

     @Override 
     public int getColumnCount() 
     { 
      return 1; 
     } 

     @Override 
     public Object getValueAt(int rowIndex, int columnIndex) 
     { 
      return data.get(rowIndex); 
     } 
    } 
} 

編輯:

我想通了自己...用SwingUtilities.invokeLater確保行排序更新後的行索引轉換完成:

@Override 
public void tableChanged(final TableModelEvent event) 
{ 
    if (event.getType() == TableModelEvent.INSERT) 
    { 
     SwingUtilities.invokeLater(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       int modelRowIndex = event.getFirstRow(); 
       int viewRowIndex = table.convertRowIndexToView(modelRowIndex); 
       System.out.println("viewRowIndex: " + viewRowIndex); 
      } 
     }); 
    } 
} 

回答

0

您是對的,表模型偵聽器以錯誤的順序被通知。我想到的最簡單的解決方案就是自己實現聽衆。至於我,我從來沒有通過擴展AbstractTableModel來實現表模型。我發現自己實現這個功能更加透明。

private class Model extends AbstractTableModel { 
    private final List<TableModelListener> listeners = new ArrayList<TableModelListener>(); 

    @Override 
    public void addTableModelListener(TableModelListener l) { 
     listeners.add(l); 
    } 

    @Override 
    public void fireTableRowsInserted(int firstRow, int lastRow) { 
     for (TableModelListener l : listeners) { 
      l.tableChanged(new TableModelEvent(Model.this, firstRow, 
        lastRow, TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT)); 
     } 
    } 
    ... 
} 
+0

雖然這有效,但我認爲依靠聽衆通知的順序通常是一個壞主意。看到我自己的問題的編輯爲解決方案,避免這一點。儘管如此,謝謝你的回答! – thofou76