2012-12-17 54 views
4

我有JTable使用AbstractTableModel其中我有一個JCheckBox在第一列中選​​擇行。現在,我需要從被檢查的表中選擇所選的行。現在,我按順序從第一行遍歷到最後一行,並讓所有被選擇類似下面的行,使用AbstractTableModel獲取選定的行JTable使用AbstractTableModel

List<Integer> selectedRows = new ArrayList<Integer>(); 
for(int i = 0; i < table.getRowCount(); i++) { 
    if((Boolean) table.getValuAt(i, 0)) { 
     selectedRows.add(i); 
    } 
} 

這裏的問題是,我需要的時候曾經我需要遍歷所有的行獲取選定的行。現在我有10到20行。但將來我將獲得5000行左右。我的問題是,如果有5000行,並且用戶只選擇了5000nd(最後一條記錄)行,那麼我需要遍歷所有5000行以獲取選定的行。我認爲這不是一個好方法。

一種方法,我想實現的,一個監聽器添加到JCheckBox列,這樣,當曾經有改變(SELECTED/DESELECTED)然後我需要更新我的監聽器類所選行的陣列。在此聽衆類中,當用戶選擇JCheckBox時,我需要撥打table.getSelectedRow(..),如果選擇JCheckBox,則需要存儲。

有沒有更好的方法?

+0

增強模型:它可以保持/同步它的「選擇」含有一個內部數據結構(又名:具有布爾在第一列真)在setValueAt(...) – kleopatra

+0

感謝。然而,要回顧一個布爾值爲true的我需要遍歷右邊? – Amarnath

+1

如果您使用TableModel,您基本上可以使用相同的方法來保存所選行的數組。唯一不同的是,您可以從TableModel的setValueAt()方法更新它。 –

回答

8

在下面的示例中,TableModel在執行setValueAt()時更新了Set<Integer> checked。相鄰的JList的模型會偵聽表格的模型並顯示當前選定的行號。該示例假定選定行的數量與行數相比較小。請注意使用TreeSet,其迭代器保留元素的自然順序。

image

import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.GridLayout; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Set; 
import java.util.TreeSet; 
import javax.swing.BorderFactory; 
import javax.swing.DefaultListModel; 
import javax.swing.JFrame; 
import javax.swing.JList; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.event.TableModelEvent; 
import javax.swing.event.TableModelListener; 
import javax.swing.table.AbstractTableModel; 

/** @see http://stackoverflow.com/a/13919878/230513 */ 
public class CheckTable { 

    private static final CheckModel model = new CheckModel(5000); 
    private static final JTable table = new JTable(model) { 

     @Override 
     public Dimension getPreferredScrollableViewportSize() { 
      return new Dimension(150, 300); 
     } 
    }; 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       JFrame f = new JFrame("CheckTable"); 
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       f.setLayout(new GridLayout(1, 0)); 
       f.add(new JScrollPane(table)); 
       f.add(new DisplayPanel(model)); 
       f.pack(); 
       f.setLocationRelativeTo(null); 
       f.setVisible(true); 
      } 
     }); 
    } 

    private static class DisplayPanel extends JPanel { 

     private DefaultListModel dlm = new DefaultListModel(); 
     private JList list = new JList(dlm); 

     public DisplayPanel(final CheckModel model) { 
      super(new GridLayout()); 
      this.setBorder(BorderFactory.createTitledBorder("Checked")); 
      this.add(new JScrollPane(list)); 
      model.addTableModelListener(new TableModelListener() { 

       @Override 
       public void tableChanged(TableModelEvent e) { 
        dlm.removeAllElements(); 
        for (Integer integer : model.checked) { 
         dlm.addElement(integer); 
        } 
       } 
      }); 
     } 
    } 

    private static class CheckModel extends AbstractTableModel { 

     private final int rows; 
     private List<Boolean> rowList; 
     private Set<Integer> checked = new TreeSet<Integer>(); 

     public CheckModel(int rows) { 
      this.rows = rows; 
      rowList = new ArrayList<Boolean>(rows); 
      for (int i = 0; i < rows; i++) { 
       rowList.add(Boolean.FALSE); 
      } 
     } 

     @Override 
     public int getRowCount() { 
      return rows; 
     } 

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

     @Override 
     public String getColumnName(int col) { 
      return "Column " + col; 
     } 

     @Override 
     public Object getValueAt(int row, int col) { 
      if (col == 0) { 
       return row; 
      } else { 
       return rowList.get(row); 
      } 
     } 

     @Override 
     public void setValueAt(Object aValue, int row, int col) { 
      boolean b = (Boolean) aValue; 
      rowList.set(row, b); 
      if (b) { 
       checked.add(row); 
      } else { 
       checked.remove(row); 
      } 
      fireTableRowsUpdated(row, row); 
     } 

     @Override 
     public Class<?> getColumnClass(int col) { 
      return getValueAt(0, col).getClass(); 
     } 

     @Override 
     public boolean isCellEditable(int row, int col) { 
      return col == 1; 
     } 
    } 
} 
+0

+1 ..是一個很好的習慣寫邏輯(獲取選定的行)在模型中。 B'coz所有這些天我都將TableModel從我的邏輯中分離出來。 – Amarnath

+0

這是一個權衡,對於大型模型來說當然值得分析。還要考慮'JList'或[共享模型]的'AbstractListModel'(http://stackoverflow.com/a/7572903/230513)。 – trashgod

+0

但我有這個appraoach的問題。當我刪除一些選定的行時,那些行麻煩不得不從集中刪除。但是具有前面行號的Set中的所有行數都不一致?我有功能像刪除,do_action等.. – Amarnath

3

我同意kleopatra。當您創建AbstractTableModel的子類時,您將覆蓋setValue(Object值,int rowIndex,int colIndex)。在您重寫的方法中,您只需檢查列是否與您的複選框一致,如果是,則適當地更新內部數據結構。您還可以添加一個方法getCheckedRows(),該方法返回一個列表< Integer>,其中複選框已被選中。

相關問題