java JTable 中带有复选框的多行选择

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10679425/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 02:04:14  来源:igfitidea点击:

Multiple row selection with checkbox in JTable

javaswingjtable

提问by rcnpl

I have a JTable with checkbox as one of the column. I also have a checkbox in header to check/uncheck all. AFAIK the default behaviour of JTable is it deselects all the rows selected before if select a new row. But can we achieve CTRL click like behavior with checkbox. That retaining the previously selected row. The main problem I am facing is while enabling multiple selection of JTable rows using checkbox.

我有一个带有复选框的 JTable 作为列之一。我在标题中还有一个复选框来选中/取消选中所有内容。AFAIK JTable 的默认行为是如果选择新行,它会取消选择之前选择的所有行。但是我们可以使用复选框来实现 CTRL 单击类似的行为吗?保留先前选择的行。我面临的主要问题是使用复选框启用多选 JTable 行。

Expected output

预期输出

1st row is checked then first row is selected and if third row is checked then third is selected along with first row (which is already checked and selected)

选中第一行,然后选择第一行,如果选中第三行,则选中第三行以及第一行(已选中并选中)

Actual output

实际产量

When first row is checked and selected and if select the third row then it deselects all the rows previously selected and the third one is only selected.

选中并选择第一行并且如果选择第三行,则它取消选择先前选择的所有行,并且仅选择第三行。

I have a sample code which simulates the scenario I want to achieve same as the Add Another Onebutton does, but with checkbox selection.

我有一个示例代码,它模拟了我想要实现的与Add Another One按钮相同的场景,但带有复选框选择。

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableColumn;
import javax.swing.event.CellEditorListener;

public class JTableRowSelectProgramatically extends JPanel {

final JTable table = new JTable(new MyTableModel());

public JTableRowSelectProgramatically() {
    initializePanel();
}

private void initializePanel() {
    setLayout(new BorderLayout());
    setPreferredSize(new Dimension(475, 150));


    table.setFillsViewportHeight(true);
    JScrollPane pane = new JScrollPane(table);

    JLabel label2 = new JLabel("Row: ");
    final JTextField field2 = new JTextField(3);
    JButton add = new JButton("Select");

    table.setRowSelectionAllowed(true);
    table.setColumnSelectionAllowed(false);
    table.getSelectionModel().addListSelectionListener(new ListSelectionListenerImpl());
    TableColumn tc = table.getColumnModel().getColumn(3);
    tc.setCellEditor(table.getDefaultEditor(Boolean.class));
    tc.setCellRenderer(table.getDefaultRenderer(Boolean.class));
    ((JComponent) table.getDefaultRenderer(Boolean.class)).setOpaque(true);
    tc.getCellEditor().addCellEditorListener(new CellEditorListenerImpl());

    add.addActionListener(new ActionListener() {

        public void actionPerformed(ActionEvent event) {
            int index2 = 0;
            try {
                index2 = Integer.valueOf(field2.getText());
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
            table.addRowSelectionInterval(index2, index2);
            field2.setText(String.valueOf(index2));
        }
    });

    JPanel command = new JPanel(new FlowLayout());
    command.add(label2);
    command.add(field2);
    command.add(add);

    add(pane, BorderLayout.CENTER);
    add(command, BorderLayout.SOUTH);
}

public static void showFrame() {
    JPanel panel = new JTableRowSelectProgramatically();
    panel.setOpaque(true);

    JFrame frame = new JFrame("JTable Row Selection");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setContentPane(panel);
    frame.pack();
    frame.setVisible(true);
}

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

        public void run() {
            JTableRowSelectProgramatically.showFrame();
        }
    });
}

public class MyTableModel extends AbstractTableModel {

    private String[] columns = {"ID", "NAME", "AGE", "A STUDENT?"};
    private Object[][] data = {
        {1, "Alice", 20, new Boolean(false)},
        {2, "Bob", 10, new Boolean(false)},
        {3, "Carol", 15, new Boolean(false)},
        {4, "Mallory", 25, new Boolean(false)}
    };

    public int getRowCount() {
        return data.length;
    }

    public int getColumnCount() {
        return columns.length;
    }

    public Object getValueAt(int rowIndex, int columnIndex) {
        return data[rowIndex][columnIndex];
    }

    @Override
    public String getColumnName(int column) {
        return columns[column];
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return columnIndex == 3;
    }

    //
    // This method is used by the JTable to define the default
    // renderer or editor for each cell. For example if you have
    // a boolean data it will be rendered as a check box. A
    // number value is right aligned.
    //
    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return data[0][columnIndex].getClass();
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        if (columnIndex == 3) {
            data[rowIndex][columnIndex] = aValue;
            fireTableCellUpdated(rowIndex, columnIndex);
        }
    }
}

class ListSelectionListenerImpl implements ListSelectionListener {

    public void valueChanged(ListSelectionEvent lse) {
        ListSelectionModel lsm = (ListSelectionModel) lse.getSource();
        int row = table.getRowCount();
        if (lsm.isSelectionEmpty()) {
        } else {
//                If any column is clicked other than checkbox then do normal selection
//                i.e select the click row and deselects the previous selection
            if (table.getSelectedColumn() != 3) {
                for (int i = 0; i < row; i++) {
                    if (lsm.isSelectedIndex(i)) {
                        table.setValueAt(true, i, 3);
                    } else {
                        table.setValueAt(false, i, 3);
                    }
                }

            }
        }
    }
  }
public class CellEditorListenerImpl implements CellEditorListener{

    public void editingStopped(ChangeEvent e) {
        for(int i=0; i<table.getRowCount();i++){
            if((Boolean)table.getValueAt(i, 3)){
                table.addRowSelectionInterval(i, i);
            }
            else{
                table.removeRowSelectionInterval(i, i);
            }
        }
    }

    public void editingCanceled(ChangeEvent e) {
        System.out.println("do nothing");
    }

}
}

回答by trashgod

Once you implement these TableModelmethods, you can use setValueAt()in your button listeners to condition the model as required to keep the checkbox state and selection model in synchrony. There's a related example here.

实现这些TableModel方法后,您可以setValueAt()在按钮侦听器中使用以根据需要调整模型,以保持复选框状态和选择模型同步。有一个相关的例子在这里

@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
    return columnIndex == 3;
}

@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    if (columnIndex == 3) {
        data[rowIndex][columnIndex] = aValue;
        fireTableCellUpdated(rowIndex, columnIndex);
    }
}

Addendum: As a concrete example, your clearlistener might invoke a method in the TableModelsuch as clearChecks():

附录:作为一个具体的例子,你的clear听众可能会在调用一个方法TableModel,如clearChecks()

MyTableModel model = (MyTableModel) table.getModel();
model.clearChecks();
...
private void clearChecks() {
    for (int i = 0; i < data.length; i++) {
        data[i][3] = false;
    }
    fireTableRowsUpdated(0, data.length);
}

回答by false_memories

At a high level, I would invoke a key listener and check if VK_CTRL is flagged when inside your selection listener. This sounds like a logic block issue or a listener conflict.

在高层次上,我会调用一个键侦听器并检查在选择侦听器中是否标记了 VK_CTRL。这听起来像是逻辑块问题或侦听器冲突。

Barring that, a JList box allows for multiple selections.

除此之外,JList 框允许进行多项选择。