java 使用自定义 TableModel 使 isCellEditable 在按钮单击时为特定行设置为 true

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12405605/
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 08:46:32  来源:igfitidea点击:

Using custom TableModel make isCellEditable true for a particular row on button click

javaswingjtablejbuttonabstracttablemodel

提问by Amarnath

MY Table

我的桌子

I have a table like above. Initially all the cells except button column are not editable. I have created the table using custom TableModel. My isCellEditablein custom TableModellooks like this:

我有一张像上面一样的桌子。最初,除按钮列之外的所有单元格都不可编辑。我已经使用 custom 创建了表格TableModel。我isCellEditable的自定义TableModel看起来像这样:

public boolean isCellEditable(int rowIndex, int columnIndex) { 
    //System.out.println("isCellEditable: " + rowIndex + " " + columnIndex);
    if(getColumnClass(columnIndex) == JButton.class)
        return true;
    else
        return false;
}

But when I click on the Edit button of each row a JDialogwill pop up with that row (by constructing a JTablein this dialog with only one row.) I can update the cell values in this JDialog's table. and then update them in the respective cells of that row.

但是,当我单击每一行的“编辑”按钮时,JDialog将弹出该行(通过JTable在此对话框中仅构造一行)。我可以更新此 JDialog 表中的单元格值。然后在该行的相应单元格中更新它们。

JDialog's Table

JDialog 的表

I am successfully able to update the main table's row after updating here, only if my isCellEditablereturn true. But this should not happen. Only when I click then I should be able to change isCellEditableof the row as Editable and update and then make it uneditable.

仅当我isCellEditable返回 true 时,我才能在此处更新后成功更新主表的行。但这不应该发生。只有当我点击然后我才应该能够isCellEditable将行更改为可编辑并更新,然后使其不可编辑。

I have seen the following postbut was unable to implement it.

我看过以下帖子,但无法实施。

采纳答案by kleopatra

Fleshing out my comment to the question:

充实我对这个问题的评论:

there's no need to tweak the editability of the full model: create another model populated by the filtered (column-wise) row of the original, make that other editable and on commit let it write back the changed values to the original

无需调整完整模型的可编辑性:创建另一个由原始模型的过滤(按列)行填充的模型,使其他模型可编辑,并在提交时让它将更改后的值写回原始模型

with a bit of code:

用一点代码:

public static class ButtonDialogEditor extends AbstractCellEditor 
     implements TableCellEditor {
    // the columns to present for editing, in model coordinates
    public final int lastColumn;
    public final int firstColumn;
    // the row to present for editing, in model coordinates
    private int row;

    private DefaultTableModel model;
    private JDialog dialog;
    private boolean committed;
    private JButton editingComponent;

    public ButtonDialogEditor(int firstColumn, int lastColumn) {
       this.firstColumn = firstColumn;
       this.lastColumn = lastColumn;

       model = new DefaultTableModel(1, lastColumn - firstColumn + 1);
       JTable table = new JTable(model);
       table.putClientProperty("terminateEditOnFocusLost",true);
       dialog = new JDialog();
       dialog.setModal(true);
       dialog.add(new JScrollPane(table));
       dialog.add(new JButton(createOkAction()), BorderLayout.SOUTH);
       dialog.pack();
       editingComponent = new JButton(createShowDialogAction());
    }

    /**
     * Returns the cell value at column. Note that column
     * is in the model coordinate system of the source model.
     */
    public Object getValueAt(int column) {
        return model.getValueAt(0, column - firstColumn);
    }

    /**
     * Returns the row index of the edited row in 
     * model coordinates of the source table.
     */
    public int getModelRow() {
        return row;
    }

    /**
     * Creates and returns the action used for 
     * the editing component button.
     * 
     * Implemented to show the modal dialog and fire 
     * editingSotpped/canceled depending on the committed
     * flag
     */
    private Action createShowDialogAction() {
        Action action = new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // reset committed
                committed = false;
                dialog.setVisible(true);
                if (committed) {
                    fireEditingStopped();
                } else {
                    fireEditingCanceled();
                }
            }
        };
        return action;
    }

    /**
     * Creates and returns the action used for the dialog's
     * OK button.
     * 
     * Implemented to hide the dialog and set the
     * committed flag to true.
     */
    private Action createOkAction() {
        Action action = new AbstractAction("OK") {
            @Override
            public void actionPerformed(ActionEvent e) {
                dialog.setVisible(false);
                committed = true;
            }
        };
        return action;
    }

    @Override
    public Component getTableCellEditorComponent(JTable table,
            Object value, boolean isSelected, int row, int column) {
        editingComponent.setText(value != null ? value.toString() : "");
        prepareDialog(table, row);
        return editingComponent;
    }

    /**
     * Update internal state to the row to edit. 
     */
    private void prepareDialog(JTable table, int row) {
        this.row = table.convertRowIndexToModel(row);
        for (int i = firstColumn; i <= lastColumn; i++) {
            model.setValueAt(table.getModel().getValueAt(this.row, i), 0, i - firstColumn);
        }
    }

    /**
     * Implemented to return the original value as 
     * given in the 
     */
    @Override
    public Object getCellEditorValue() {
        return editingComponent.getText();
    }

}

public static class ButtonRenderer implements TableCellRenderer {

    JButton button = new JButton();
    @Override
    public Component getTableCellRendererComponent(JTable table,
            Object value, boolean isSelected, boolean hasFocus, int row,
            int column) {
        button.setText(value != null ? value.toString() : "");
        return button;
    }
}

// example usage
// source model is not editable except for the button column
final DefaultTableModel model = new DefaultTableModel(0, 3) {
    @Override
    public boolean isCellEditable(int row, int column) {
        return column == 0;
    }
};
for (int i = 0; i < 20; i++) {
    model.addRow(new Object[] {"Edit", i});
}
JTable table = new JTable(model);
table.getColumnModel().getColumn(0).setCellRenderer(new ButtonRenderer());
final ButtonDialogEditor cellEditor = new ButtonDialogEditor(1, model.getColumnCount() - 1);
// custom editor listener which writes back the edited values
// to the model on editingStopped.
CellEditorListener l = new CellEditorListener() {

    @Override
    public void editingStopped(ChangeEvent e) {
        for (int i = cellEditor.firstColumn; i <= cellEditor.lastColumn; i++) {
            model.setValueAt(cellEditor.getValueAt(i), cellEditor.getModelRow(), i);
        }
    }

    @Override
    public void editingCanceled(ChangeEvent e) {
        // nothing to do
    }
};
cellEditor.addCellEditorListener(l);
table.getColumnModel().getColumn(0).setCellEditor(
        cellEditor);

回答by mKorbel

XxxTableModelstores String.classfor JButtonas Renderer/ Editorfor JTable

XxxTableModel存储String.class用于JButton作为Renderer/EditorJTable

and for your code (is based on) too

并且对于您的代码(基于)也是

EDIT

编辑

DefaultTableModel

默认表模型

import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;

public class TableButton3 extends JFrame {

    private static final long serialVersionUID = 1L;
    private JTable table;

    public TableButton3() {
        String[] columnNames = {"Date", "String", "Decimal", "Remove"};
        Object[][] data = {
            {new Date(), "A", new Double(5.1), "Remove"}, {new Date(), "B", new Double(6.2), "Remove"},
            {new Date(), "C", new Double(7.3), "Remove"}, {new Date(), "D", new Double(8.4), "Remove"},
            {new Date(), "A", new Double(5.1), "Remove"}, {new Date(), "B", new Double(6.2), "Remove"},};
        DefaultTableModel model = new DefaultTableModel(data, columnNames){

            private static final long serialVersionUID = 1L;

            @Override//  Returning the Class of each column will allow different renderers to be used based on Class
            public Class getColumnClass(int column) {
                switch (column) {
                    case 0:
                        return Date.class;
                    case 2:
                        return Double.class;
                    default:
                        return String.class;
                }
                //return getValueAt(0, column).getClass();
            }
        };
        table = new JTable(model) ;
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane(table);
        getContentPane().add(scrollPane);
        ButtonColumn buttonColumn = new ButtonColumn(table, delete, 3);
        buttonColumn.setMnemonic(KeyEvent.VK_D);
    }

    public static void main(String[] args) {
        TableButton3 frame = new TableButton3();
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
    //
    private Action delete = new AbstractAction() {

        private static final long serialVersionUID = 1L;

        public void actionPerformed(ActionEvent e) {
            JTable table = (JTable) e.getSource();
            int modelRow = Integer.valueOf(e.getActionCommand());
            ((DefaultTableModel) table.getModel()).removeRow(modelRow);
            table.clearSelection();
        }
    };
}

AbstractTableModel

抽象表模型

import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;

public class TableButton3 extends JFrame {

    private static final long serialVersionUID = 1L;
    private JTable table;
    private MyTableModel myModel = new MyTableModel();

    public TableButton3() {
        String[] columnNames = {"Date", "String", "Decimal", "Remove"};
        Object[][] data = {
            {new Date(), "A", new Double(5.1), "Remove"}, {new Date(), "B", new Double(6.2), "Remove"},
            {new Date(), "C", new Double(7.3), "Remove"}, {new Date(), "D", new Double(8.4), "Remove"},
            {new Date(), "A", new Double(5.1), "Remove"}, {new Date(), "B", new Double(6.2), "Remove"},};
        DefaultTableModel model = new DefaultTableModel(data, columnNames){

            private static final long serialVersionUID = 1L;

            @Override//  Returning the Class of each column will allow different renderers to be used based on Class
            public Class getColumnClass(int column) {
                switch (column) {
                    case 0:
                        return Date.class;
                    case 2:
                        return Double.class;
                    default:
                        return String.class;
                }
                //return getValueAt(0, column).getClass();
            }
        };
        table = new JTable(model);
        table = new JTable(myModel);
        addTableDatas();
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane);
        ButtonColumn buttonColumn = new ButtonColumn(table, delete, 3);
        buttonColumn.setMnemonic(KeyEvent.VK_D);
    }

    public static void main(String[] args) {
        TableButton3 frame = new TableButton3();
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    private void addTableDatas() {
        Vector<String> columnNameS = new Vector<String>();
        columnNameS.add("Date");
        columnNameS.add("String");
        columnNameS.add("Decimal");
        columnNameS.add("Remove");
        myModel.setColumnNames(columnNameS);

        Vector<Object> row1 = new Vector<Object>();
        row1.add(new Date());
        row1.add("A");
        row1.add(new Double(5.1));
        row1.add("Remove");
        myModel.addRow(row1);

        row1 = new Vector<Object>();
        row1.add(new Date());
        row1.add("B");
        row1.add(new Double(6.2));
        row1.add("Remove");
        myModel.addRow(row1);

        row1 = new Vector<Object>();
        row1.add(new Date());
        row1.add("B");
        row1.add(new Double(8.4));
        row1.add("Remove");
        myModel.addRow(row1);

        row1 = new Vector<Object>();
        row1.add(new Date());
        row1.add("B");
        row1.add(new Double(5.1));
        row1.add("Remove");
        myModel.addRow(row1);

        row1 = new Vector<Object>();
        row1.add(new Date());
        row1.add("B");
        row1.add(new Double(6.2));
        row1.add("Remove");
        myModel.addRow(row1);
    }

    private class MyTableModel extends AbstractTableModel {

        private static final long serialVersionUID = 1L;
        private Vector<Vector<Object>> data;
        private Vector<String> colNames;
        private boolean[] _columnsVisible = {true, true, true, true};

        public MyTableModel() {
            this.colNames = new Vector<String>();
            this.data = new Vector<Vector<Object>>();
        }

        public MyTableModel(Vector<String> colnames) {
            this.colNames = colnames;
            this.data = new Vector<Vector<Object>>();
        }

        public void resetTable() {
            this.colNames.removeAllElements();
            this.data.removeAllElements();
        }

        public void setColumnNames(Vector<String> colNames) {
            this.colNames = colNames;
            this.fireTableStructureChanged();
        }

        public void addRow(Vector<Object> data) {
            this.data.add(data);
            this.fireTableRowsInserted(data.size() - 1, data.size() - 1);
        }

        public void removeRowAt(int row) {
            this.data.removeElementAt(row);
            this.fireTableRowsDeleted(row - 1, data.size() - 1);
        }

        @Override
        public int getColumnCount() {
            return this.colNames.size();
        }

        @Override
        public Class<?> getColumnClass(int colNum) {
            switch (colNum) {
                case 0:
                    return Date.class;
                case 2:
                    return Double.class;
                default:
                    return String.class;
            }
        }

        @Override
        public boolean isCellEditable(int row, int colNum) {
            switch (colNum) {
                default:
                    return true;
            }
        }

        @Override
        public String getColumnName(int colNum) {
            return this.colNames.get(colNum);
        }

        @Override
        public int getRowCount() {
            return this.data.size();
        }

        @Override
        public Object getValueAt(int row, int col) {
            Vector<Object> value = this.data.get(row);
            return value.get(col);
        }

        @Override
        public void setValueAt(Object newVal, int row, int col) {
            Vector<Object> aRow = data.elementAt(row);
            aRow.remove(col);
            aRow.insertElementAt(newVal, col);
            fireTableCellUpdated(row, col);
        }

        public void setColumnVisible(int index, boolean visible) {
            this._columnsVisible[index] = visible;
            this.fireTableStructureChanged();
        }
    }
    //
    private Action delete = new AbstractAction() {

        private static final long serialVersionUID = 1L;

        public void actionPerformed(ActionEvent e) {
            JTable table = (JTable) e.getSource();
            int modelRow = Integer.valueOf(e.getActionCommand());
            ((DefaultTableModel) table.getModel()).removeRow(modelRow);
            table.clearSelection();
        }
    };
}

both returns the same GUI, with the same ...

两者都返回相同的 GUI,具有相同的 ...

enter image description here

在此处输入图片说明