【问题标题】:Multiple row selection in JTableJTable中的多行选择
【发布时间】:2011-05-30 10:23:01
【问题描述】:

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

【问题讨论】:

    标签: java swing user-interface jtable jcheckbox


    【解决方案1】:

    你可以用类似这样的代码得到选择区间:

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

    然后,当检查一个复选框时(收听ItemEvent),您应该从minSelectedRow到maxSelectedRow并更改选中框状态。就是这样。

    【讨论】:

      【解决方案2】:

      问题是当你点击一个复选框来改变复选框的值时,所有行的选择都会丢失。因此,您可能需要使用鼠标右键单击以显示包含选择/取消选择值的弹出菜单。

      然后你可以使用table.getSelectedRows(),来获取你需要更新的所有选中行的索引。

      【讨论】:

      • 你是对的......当复选框被点击时,所有的行选择都会丢失......如果不使用右键点击有什么办法解决这个问题......?
      • 您不能使用鼠标单击来实现两个不同的功能。解决方案是适当的用户界面。我提出了一个使用弹出菜单的建议。另一种解决方案是使用带有加速器的菜单中的 menuItems 来选择/取消选择。这样用户可以使用鼠标或键盘。或者您可以在 UI 中添加按钮来执行相同的操作。
      • 我必须同意@camickr;我在附近添加了一个示例。
      【解决方案3】:

      我同意 Roman 的观点,即如果您使用类字段来保存最小和最大选择,他的想法会奏效。例如:

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

      【讨论】:

      • @Hovercraft Full Of Eels 虽然你的代码是有道理的,但当我在我的系统上执行时,它的行为非常出乎意料,束选择工作得很好,但之后正常选择也会触发束选择......
      • @Hovercraft Full Of Eels 复选框 2,取消选中框 2,然后取消选中框 4.....然后自动选中框 2......
      • 我并不感到惊讶,因为如果仍然选择 2 会发生这种情况,我认为这是程序所需的行为:如果选中或取消选中复选框,所有选定的行都会模仿该检查框的状态,包括最后一次选择留下的单个选定行。如果您不希望这种行为,一种解决方法是在 TableModelListener 的 tableChanged 方法的末尾将最小和最大选定行设置为 -1。我将更新下面的代码以向您展示我的意思。
      • +1 好例子。它按描述工作,但它只处理连续的选择。​​
      • 您当然是对的,感谢您的见解。让我看看我能做什么......
      【解决方案4】:

      使用@Hovercraft 的示例和@camickr 的建议,下面的示例显示了一个合适的用户界面。虽然它使用按钮,但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();
                  }
              });
          }
      }
      

      【讨论】:

      • 如果启用了sorting,请查看 cmets here。
      • 您好,很抱歉回复您,但我不久前才发现这个问题,并希望在添加监听器以了解列表中的更改时提供一些意见。现在我正在使用 mouseListener,但它在列表实际更新之前触发。如何添加侦听器以在列表发生更新时获取更新?
      • 可能是TableCellEditor,见过here?
      猜你喜欢
      • 2012-05-27
      • 2018-10-30
      • 2023-03-24
      • 1970-01-01
      • 2012-06-25
      • 2012-02-20
      • 1970-01-01
      • 2014-09-07
      • 1970-01-01
      相关资源
      最近更新 更多