4

行を選択するために最初の列にある場所をJTable使用しています。ここで、チェックされているテーブルから選択された行を取得する必要があります。現在、最初の行から最後の行まで順番にトラバースし、次のように選択されているすべての行を取得しています。AbstractTableModelJCheckBox

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 行があり、ユーザーが 5000 番目 (最後のレコード) 行のみを選択した場合、5000 行すべてを走査して選択した行を取得する必要があるということです。これは良いアプローチではないと思います。

実装したいアプローチの 1 つは、JCheckBox列にリスナーを追加することです。これにより、変更がある(SELECTED/DESELECTED)たびに、リスナー クラスで選択した行の配列を更新する必要があります。このリスナー クラスでは、ユーザーが を選択するたびJCheckBoxに呼び出す必要がtable.getSelectedRow(..)あり、それが選択されている場合は保存する必要がありJCheckBoxます。

より良いアプローチはありますか?

4

2 に答える 2

8

以下の例では、は の実装でTableModela を更新します。隣接するモデルは、テーブルのモデルをリッスンし、現在選択されている行番号を表示します。この例では、選択された行の数が行の数に比べて少ないことを前提としています。の使用に注意してください。その反復子は、要素の自然な順序を保持します。Set<Integer> checkedsetValueAt()JListTreeSet

画像

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;
        }
    }
}
于 2012-12-17T18:27:07.600 に答える
3

私はクレオパトラに同意します。AbstractTableModel のサブクラスを作成するときは、setValue( Object value, int rowIndex, int colIndex ) をオーバーライドします。オーバーライドされたメソッドでは、列がチェック ボックスのある列であるかどうかを確認し、そうであれば、内部データ構造を適切に更新します。チェックボックスが選択されている行を含む List< Integer > を返すメソッド getCheckedRows() を追加することもできます。

于 2012-12-17T14:03:57.073 に答える