简体   繁体   English

JTable中的多行选择

[英]Multiple row selection in JTable

我有一个 JTable,它有一列是不可编辑的文本,第二列是一个显示布尔值的复选框......现在我想要的是,当用户选择多行并取消选中任何一个选中的复选框,则选择下的所有复选框都应取消选中,反之亦然。

Using @Hovercraft's example and @camickr's advice, the example below shows a suitable user interface.使用@Hovercraft 的示例和@camickr 的建议,下面的示例显示了一个合适的用户界面。 Although it uses buttons, the SelectionAction would also be suitable for a menu or popup.尽管它使用按钮,但SelectionAction也适用于菜单或弹出窗口。

检查一堆

import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.DefaultListSelectionModel;
import javax.swing.table.DefaultTableModel;

/** @see http://stackoverflow.com/questions/4526779 */
public class CheckABunch extends JPanel {

    private static final int CHECK_COL = 1;
    private static final Object[][] DATA = {
        {"One", Boolean.TRUE}, {"Two", Boolean.FALSE},
        {"Three", Boolean.TRUE}, {"Four", Boolean.FALSE},
        {"Five", Boolean.TRUE}, {"Six", Boolean.FALSE},
        {"Seven", Boolean.TRUE}, {"Eight", Boolean.FALSE},
        {"Nine", Boolean.TRUE}, {"Ten", Boolean.FALSE}};
    private static final String[] COLUMNS = {"Number", "CheckBox"};
    private DataModel dataModel = new DataModel(DATA, COLUMNS);
    private JTable table = new JTable(dataModel);
    private DefaultListSelectionModel selectionModel;

    public CheckABunch() {
        super(new BorderLayout());
        this.add(new JScrollPane(table));
        this.add(new ControlPanel(), BorderLayout.SOUTH);
        table.setPreferredScrollableViewportSize(new Dimension(250, 175));
        selectionModel = (DefaultListSelectionModel) table.getSelectionModel();
    }

    private class DataModel extends DefaultTableModel {

        public DataModel(Object[][] data, Object[] columnNames) {
            super(data, columnNames);
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            if (columnIndex == CHECK_COL) {
                return getValueAt(0, CHECK_COL).getClass();
            }
            return super.getColumnClass(columnIndex);
        }

        @Override
        public boolean isCellEditable(int row, int column) {
            return column == CHECK_COL;
        }
    }

    private class ControlPanel extends JPanel {

        public ControlPanel() {
            this.add(new JLabel("Selection:"));
            this.add(new JButton(new SelectionAction("Clear", false)));
            this.add(new JButton(new SelectionAction("Check", true)));
        }
    }

    private class SelectionAction extends AbstractAction {

        boolean value;

        public SelectionAction(String name, boolean value) {
            super(name);
            this.value = value;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            for (int i = 0; i < dataModel.getRowCount(); i++) {
                if (selectionModel.isSelectedIndex(i)) {
                    dataModel.setValueAt(value, i, CHECK_COL);
                }
            }
        }
    }

    private static void createAndShowUI() {
        JFrame frame = new JFrame("CheckABunch");
        frame.add(new CheckABunch());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

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

            @Override
            public void run() {
                createAndShowUI();
            }
        });
    }
}

The problem is that when you click on a check box to change the value of the check box, the selection of all the rows will be lost.问题是当你点击一个复选框来改变复选框的值时,所有行的选择都会丢失。 So you may need to use a right mouse click to display a popup menu that contains select/deselect values.因此,您可能需要使用鼠标右键单击来显示包含选择/取消选择值的弹出菜单。

Then you can use table.getSelectedRows(), to get the indexes of all the selected rows you need to update.然后您可以使用 table.getSelectedRows() 来获取您需要更新的所有选定行的索引。

You can get the selection interval with code similar to this:您可以使用类似于此的代码获取选择间隔:

table.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
    public void valueChanged(ListSelectionEvent e) {
        minSelectedRow = ((DefaultListSelectionModel)e.getSource()).getMinSelectionIndex();
        maxSelectedRow = ((DefaultListSelectionModel)e.getSource()).getMaxSelectionIndex();
    }
});

Then, when one checkbox is checked (listen to ItemEvent ) you should iterate from the minSelectedRow to the maxSelectedRow and change checked boxes state.然后,当一个复选框被选中(听ItemEvent ),你应该从迭代minSelectedRowmaxSelectedRow和变化检测盒的状态。 That's it.就是这样。

I agree with Roman that his idea would work if you use a class field to hold the min and max selection.我同意 Roman 的观点,如果您使用类字段来保存最小和最大选择,他的想法就会奏效。 For instance:例如:

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;

public class CheckABunch extends JPanel {
    private static final Object[][] DATA = {{"One", Boolean.TRUE}, {"Two", Boolean.FALSE},
        {"Three", Boolean.TRUE}, {"Four", Boolean.FALSE}, {"Five", Boolean.TRUE},
        {"Six", Boolean.FALSE}, {"Seven", Boolean.TRUE}, {"Eight", Boolean.FALSE}};
    private static final String[] COLUMNS = {"Number", "CheckBox"};
    private DefaultTableModel model = new DefaultTableModel(DATA, COLUMNS) {
        @Override
        public Class<?> getColumnClass(int columnIndex) {
            if (columnIndex == 1) {
                return getValueAt(0, 1).getClass();
            }
            return super.getColumnClass(columnIndex);
        }
    };
    private JTable table = new JTable(model);
    private int minSelectedRow = -1;
    private int maxSelectedRow = -1;
    boolean tableModelListenerIsChanging = false;

    public CheckABunch() {
        add(new JScrollPane(table));

        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if (e.getValueIsAdjusting()) {
                    return;
                }
                minSelectedRow = ((DefaultListSelectionModel) e.getSource()).getMinSelectionIndex();
                maxSelectedRow = ((DefaultListSelectionModel) e.getSource()).getMaxSelectionIndex();
            }
        });

        model.addTableModelListener(new TableModelListener() {
            public void tableChanged(TableModelEvent e) {
                if (tableModelListenerIsChanging) {
                    return;
                }                
                int firstRow = e.getFirstRow();
                int column = e.getColumn();

                if (column != 1 || maxSelectedRow == -1 || minSelectedRow == -1) {
                    return;
                }
                tableModelListenerIsChanging = true;
                boolean value = ((Boolean)model.getValueAt(firstRow, column)).booleanValue();
                for (int i = minSelectedRow; i <= maxSelectedRow; i++) {
                    model.setValueAt(Boolean.valueOf(value), i, column);
                }

                // *** edit: added two lines
                minSelectedRow = -1;
                maxSelectedRow = -1;

                tableModelListenerIsChanging = false;
            }
        });
    }

    private static void createAndShowUI() {
        JFrame frame = new JFrame("CheckABunch");
        frame.getContentPane().add(new CheckABunch());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                createAndShowUI();
            }
        });
    }
}

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

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