简体   繁体   English

Swing JTable中的多单元选择

[英]Multi-cell selection in a Swing JTable

I want to provide multi-cell editing functionality to a JTable: double click will still edit the value in the selected cell (the standard behavior), while right-click should open up a popup menu with an entry "Edit selected cells". 我想为JTable提供多单元格编辑功能:双击仍将编辑所选单元格中的值(标准行为),而右键单击则应打开一个带有“编辑所选单元格”条目的弹出菜单。

When the user hits this menu entry, the last cell in the selected range becomes editable. 当用户点击此菜单条目时,所选范围中的最后一个单元格变为可编辑。 The other selected cells remain selected. 其他选定的单元格保持选中状态 Then they write the new value and, when the edition is finished (usually by hitting Enter), all of the selected cells get this value. 然后他们编写新值,并在编辑完成后(通常按Enter键),所有选定的单元格都会获得此值。

Let's assume, for simplicity, that all cells contain the same value types, say, integers. 为简单起见,我们假设所有单元格都包含相同的值类型,例如整数。

Here's the code that shows up the popup dialog, to get started: 这是显示弹出对话框的代码,以便开始:

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

How can I do such a thing? 我该怎么办?

still not quite sure what the problem is. 仍不太确定问题是什么。 The basic approach would be 基本方法是

  • store the selected cells 存储选定的单元格
  • let the user edit one of them 让用户编辑其中一个
  • at the end, take the edited value and set it to all cells formerly stored 最后,获取编辑后的值并将其设置为以前存储的所有单元格

The only tricky part that I see might be detecting "at the end" (because the life-cycle of editing isn't overly well defined). 我看到的唯一棘手的部分可能是“在最后”检测(因为编辑的生命周期没有过分定义)。 Some code-snippet 一些代码片段

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

I would extend JTable to create MultiCellEditJTable 我会扩展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)
            );
        }
    }
}

When multiple rows of one column are selected and an edit completes, the all of the selected cells are set to the value resulting from the edit. 当选择一列的多行并完成编辑时,所有选定的单元格都将设置为编辑产生的值。

As an added bonus I made the editor selectAll to provide the function of just being able to type the desired value after selecting a range of cells. 作为一个额外的好处,我让编辑器selectAll提供了在选择一系列单元格后能够输入所需值的功能。 Otherwise one would have to backspace the current value first. 否则,必须首先对当前值进行退格。

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

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