【问题标题】:Multi-cell selection in a Swing JTableSwing JTable 中的多单元格选择
【发布时间】:2018-03-29 04:31:28
【问题描述】:

我想为 JTable 提供多单元格编辑功能:双击仍将编辑选定单元格中的值(标准行为),而右键单击应打开一个弹出菜单,其中包含“编辑选定单元格”条目”。

当用户点击此菜单项时,所选范围内的最后一个单元格变为可编辑。其他选定的单元格保持选中状态。然后他们写入新值,当编辑完成时(通常按 Enter 键),所有选定的单元格都会得到这个值。

为简单起见,我们假设所有单元格都包含相同的值类型,例如整数。

这是显示弹出对话框的代码,开始:

table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
table.setCellSelectionEnabled(true);
table.addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
        if (e.isPopupTrigger()) {
            doPop(e);
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        if (e.isPopupTrigger()) {
            doPop(e);
        }
    }

    private void doPop(MouseEvent e) {
        MultiEditPopUp menu = new MultiEditPopUp(tblRanges);
        menu.show(e.getComponent(), e.getX(), e.getY());
    }
});


class MultiEditPopUp extends JPopupMenu {
    JMenuItem menuItem;

    MultiEditPopUp(JTable table) {
        menuItem = new JMenuItem("Edit selected");
        menuItem.setAction(new BulkEditAction(table));
        add(menuItem);
    }
}

class BulkEditAction extends AbstractAction {
    private final JTable table;

    public BulkEditAction(JTable table) {
        this.table = table;
    }

    @Override
    public void actionPerformed(ActionEvent actionEvent) {
        // TODO: let the user edit the last cell, and then apply to the others
    }
}

我怎么能做这样的事?

【问题讨论】:

  • 到底是什么问题?收到编辑后的值时,将其传播到所有选定的单元格并开心:-)
  • 几个 cmets(与我没有得到的问题无关 ;-) a)不要子类化任何 JSomething,而是使用它们(JPopupMenu 旨在添加操作/项目,没有需要子类化只是为了添加一个特定的项目)b)总是使用最高的抽象,这里可用,这意味着 setComponentPopupMenu 而不是 mouseListener (无论如何,它提供了不完整的功能,因为它不包括键盘弹出窗口)
  • 问题是现在如何让用户编辑该单元格,同时保持选择。感谢您对子类化的建议。

标签: java swing jtable


【解决方案1】:

仍然不太确定问题出在哪里。基本方法是

  • 存储选定的单元格
  • 让用户编辑其中一个
  • 最后,获取编辑后的值并将其设置为之前存储的所有单元格

我看到的唯一棘手的部分可能是“在最后”检测(因为编辑的生命周期没有被过度定义)。一些代码-sn-p

public class BulkEditAction extends AbstractAction {
    JTable table;
    List selectedCells;

    public BulkEditAction(JTable table) {
        this.table = table;
    }

    @Override
    public void actionPerformed(ActionEvent actionEvent) {

        // store, here rows only, refine for cell selection
        selectedCells = Arrays.asList(table.getSelectedRows());
        final int rowToEdit =  // ...
        final int columnToEdit = // ...
        table.editCellAt(rowToEdit, columnToEdit);
        CellEditorListener l = new CellEditorListener() {

            @Override
            public void editingStopped(ChangeEvent e) {
                ((AbstractCellEditor) e.getSource()).removeCellEditorListener(this);
                propagateEditedValue(rowToEdit, columnToEdit);

            }

            @Override
            public void editingCanceled(ChangeEvent e) {
                ((AbstractCellEditor) e.getSource()).removeCellEditorListener(this);
            }
        };
        table.getCellEditor().addCellEditorListener(l);
    }

    private void propagateEditedValue(final int row, final int column) {
        // need to invoke to be sure that the table has updated itself after
        // editingStopped
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                // foreach selectedCell (with coordinates selectedRow/-column
                table.setValueAt(table.getValueAt(row, column), selectedRow, selectedColumn);
            }
        });
    }
}

【讨论】:

  • 非常好的解决方案,这就像一个魅力。我正在尝试解决用户体验问题:当您编辑该单元格时,“全选”不起作用,更糟糕的是,如果您按一个箭头,光标会移动,并且会执行批量编辑。如果我能管理,我会回帖补充这个答案。有什么想法吗?
【解决方案2】:

我会扩展 JTable 来创建 MultiCellEditJTable

public class MultiCellEditJTable extends JTable{

    public MultiCellEditJTable(){
        setColumnSelectionAllowed(true);
        getSelectionModel().setSelectionMode(DefaultListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    }


    @Override
    public Component prepareEditor(TableCellEditor editor, int row, int column){
        Component component = super.prepareEditor(editor, row, column);

        if(component instanceof JTextField){
            JTextField textField = (JTextField)component;
            textField.selectAll();
        }

        return component;
    }


    @Override
    public void editingStopped(ChangeEvent e){
        int editingRow = getEditingRow();
        int editingColumn = getEditingColumn();

        super.editingStopped(e);

        if(1 < getSelectedRowCount() && 1 == getSelectedColumnCount() && editingColumn == getSelectedColumn()){
            Object value = getValueAt(editingRow, editingColumn);
            Arrays.stream(getSelectedRows()).filter(row->row != editingRow).forEach(row->
              setValueAt(value, row, editingColumn)
            );
        }
    }
}

选择一列的多行并完成编辑时,所有选定的单元格都设置为由编辑产生的值。

作为额外的奖励,我让编辑器 selectAll 提供了在选择一系列单元格后能够键入所需值的功能。否则必须先退格当前值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-11
    • 1970-01-01
    • 2015-12-24
    • 1970-01-01
    • 1970-01-01
    • 2011-11-03
    • 1970-01-01
    • 2016-05-15
    相关资源
    最近更新 更多