简体   繁体   English

使用AbstractTableModel获取JTable中的选定行

[英]Get Selected Rows in JTable using AbstractTableModel

I have a JTable using AbstractTableModel where I have a JCheckBox in the first column for selecting rows. 我有一个使用AbstractTableModelJTable ,其中第一列中有一个JCheckBox用于选择行。 Now, I need to get the selected rows from the table which are checked. 现在,我需要从表中获取选中的行。 Right now, I am sequentially traversing from first row to the last row and getting all the rows that are selected like the following, 现在,我依次从第一行移至最后一行,并获得所有被选择的行,如下所示,

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

The problem here is, I need to traverse all the rows when ever I need to get the selected rows. 这里的问题是,当我需要获取选定的行时,我需要遍历所有行。 Right now I am having 10 to 20 rows. 现在我有10到20行。 But in future I will get around 5000 rows. 但是将来我会得到大约5000行。 My question is, if there are 5000 rows and if the user selects only 5000nd (last record) row then I need to traverse all the 5000 rows to get the selected row. 我的问题是,如果有5000行,并且如果用户仅选择5000nd(最后一条记录)行,那么我需要遍历所有5000行以获得所选行。 Which I think is not a good approach. 我认为这不是一个好方法。

One approach which I want to implement is, to add a listener to the JCheckBox column, such that when ever there is a change (SELECTED/DESELECTED) then I need to update my array of the selected rows in the listener class. 我要实现的一种方法是将侦听器添加到JCheckBox列,这样,只要发生更改(SELECTED/DESELECTED)我就需要更新侦听器类中所选行的数组。 In this listener class when ever user selectes a JCheckBox I need to call table.getSelectedRow(..) and I need to store if that JCheckBox is selected. 在此侦听器类中,当用户选择JCheckBox我需要调用table.getSelectedRow(..)并且需要存储是否选择了该JCheckBox

Are there any better approaches ? 有没有更好的方法?

In the example below, the TableModel updates a Set<Integer> checked in the implementation of setValueAt() . 在下面的示例中, TableModel更新在setValueAt()的实现中Set<Integer> checkedSet<Integer> checked The model of an adjacent JList listens to the table's model and displays the currently selected row numbers. 相邻JList的模型侦听表的模型并显示当前选择的行号。 The example assumes that the number of selected rows is small compared to the number of rows. 该示例假定所选行数比行数少。 Note the use of TreeSet , whose iterator retains the natural order of the elements. 注意使用TreeSet ,其迭代器保留元素的自然顺序。

图片

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;
        }
    }
}

I agree with kleopatra. 我同意kleopatra。 When you create a subclass of the AbstractTableModel, you'll override the setValue( Object value, int rowIndex, int colIndex ). 创建AbstractTableModel的子类时,将覆盖setValue(对象值,int rowIndex,int colIndex)。 In your overridden method, you just check if the column is the one with your check box, and if so, update the internal data structure appropriately. 在覆盖的方法中,您只需检查该列是否与复选框对应,如果是,则适当地更新内部数据结构。 You can also add a method getCheckedRows() that returns a List< Integer > with the rows in which the check boxes have been selected. 您还可以添加方法getCheckedRows(),该方法将返回List <Integer>,其中包含已选中复选框的行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM