【问题标题】:Add a row to JTable once the last cell has lost focus最后一个单元格失去焦点后向 JTable 添加一行
【发布时间】:2014-05-20 16:43:37
【问题描述】:

关于如何在最后一列失去焦点后向 JTable 添加另一行以考虑可移动列的任何建议?

注意:该表格由用户输入填充,但我只想在当前行填写完毕后显示一个新的空行。

【问题讨论】:

  • 列的重新排序或选择状态如何以任何方式影响您填充表格的方法?
  • 表格由用户输入填充,但我只想在当前行填写完毕后显示一个新的空行。
  • 好吧,这更有意义,记住在写你的问题时,我们对你在做什么一无所知。我可以立即想到几个方法,当您的 CellEditor 停止编辑或使用 TableModelListener 时,在数据更改时,检查您是否要向表中添加一个新的空行(即:您正在编辑最后一行并且您已经完成了)。第一个可能更干净。您可能还希望将焦点传递到新行的第一个单元格。问题是当您不想添加更多行时会发生什么,最后是否留下了一个空行?

标签: java swing jtable


【解决方案1】:

我制作了一个按要求运行的简单应用程序:

  • 您可以编辑任何单元格,一旦最后一行编辑的最后一个单元格结束,就会添加一个空行。

  • 它支持列重新排序(无需为此付出额外努力)。

这个方法其实很简单,JTable 实现了CellEditorListener,所以我们可以重写editingStopped(ChangeEvent) 方法并检查我们是否在表格的最后一个单元格中,如果是则添加一个新行。

所以你应该这样做:

//In the JTable class    
    @Override
    public void editingStopped(ChangeEvent e) 
    {
        //getting these values before calling super.editingStopped(e); because they get erased.
        int row = getEditingRow();
        int col = getEditingColumn();
        super.editingStopped(e); //must call the super code to have a working edition
        if (row == getRowCount() - 1 && col == getColumnCount() - 1)
        {
            getModel().createNewRow();
        }
    };

显然,我实现的 TableModel 和 TableCellEditor 和 JTable 是完成此任务的最低要求,您可以使用自己的,只需将调用更改为我为您使用的模型即可。

看起来像这样:

我建议使用 TAB 完成编辑,以便焦点转到下一个,当您处于最后一个时,它会跳转到新行的第一行。

完整代码:

import java.awt.Component;
import java.util.ArrayList;

import javax.swing.AbstractCellEditor;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;


public class TableEditingTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new TableEditingTest().createAndShowGUI();
            }
        });
    }

    private void createAndShowGUI()
    {
        JFrame frame = new JFrame("Table editing test");

        MyTableModel model = new MyTableModel();
        model.addRow(new String[]{"Some values", "so we have", "an actual table."});
        model.addRow(new String[]{"This table", "is inititalized", "with an empty row:"});
        model.createNewRow();

        MyTable table = new MyTable(model);

        table.setDefaultEditor(String.class, new MyStringTableCellEditor());

        frame.add(new JScrollPane(table));

        frame.setSize(600, 400); //use frame.pack() in a real application
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    private class MyTable extends JTable
    {
        public MyTable(MyTableModel model)
        {
            super(model);
        }

        @Override
        public MyTableModel getModel()
        {
            return (MyTableModel) super.getModel();
        }

        @Override
        public void editingStopped(ChangeEvent e) 
        {
            int row = getEditingRow();
            int col = getEditingColumn();
            super.editingStopped(e);
            if (row == getRowCount() - 1 && col == getColumnCount() - 1)
            {
                getModel().createNewRow();
            }   
        };
    }

    private class MyTableModel extends AbstractTableModel
    {
        private static final int NUMBER_OF_COLUMNS = 3;
        private ArrayList<String[]> values;


        public MyTableModel()
        {
            values = new ArrayList<String[]>();
        }

        @Override
        public String getColumnName(int col)
        {
            return "Column " + col;
        }

        @Override
        public int getColumnCount()
        {
            return NUMBER_OF_COLUMNS;
        }

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

        @Override
        public Class<?> getColumnClass(int col)
        {
            return String.class;
        }

        @Override
        public boolean isCellEditable(int row, int col) 
        {
            return true;
        };

        @Override
        public Object getValueAt(int row, int col)
        {
            return values.get(row)[col];
        }

        public void createNewRow()
        {
            addRow(null);
        }

        public void addRow(String[] rowValues)
        {
            if (rowValues == null) 
            {
                values.add(new String[3]);
                fireTableDataChanged();
            }
            else if (rowValues.length == 3)
            {
                values.add(rowValues);
                fireTableDataChanged();
            }
            else throw new IllegalArgumentException("Expected an array of " + NUMBER_OF_COLUMNS + " strings, got " + rowValues.length + ".");
        }

        @Override
        public void setValueAt(Object value, int row, int col)
        {
            values.get(row)[col] = value.toString();
        }
    }

    private class MyStringTableCellEditor extends AbstractCellEditor implements TableCellEditor
    {
        private JTextField editorField = new JTextField();

        @Override
        public Object getCellEditorValue()
        {
            return editorField.getText();
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
        {
            editorField.setText((String) value);
            return editorField;
        }
    }

}

【讨论】:

    【解决方案2】:

    我个人建议你应该使用TABActionMap 而不是使用焦点丢失。

    要添加新行,您可以使用 DeafultTableModel

     public void addNewRow(){
         DefaultTableModel model = (DefaultTableModel) jTable1.getModel();
           Vector row = new Vector();
           row.add(null);
           row.add(null);
           row.add(null);
           model.addRow(row);
        }  
    

    对于可以执行上述方法的触发器,您可以使用InputMap & ActionMap

     private class NextCellActioin extends AbstractAction{
    
        public NextCellActioin() {
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
           int col = jTable1.getSelectedColumn();
           int row =jTable1.getSelectedRow();
           int colCount = jTable1.getColumnCount();
           int rowCount = jTable1.getRowCount(); 
             col++;
            if (col >= colCount) {
                col = 0;
                row++;
            }
            if (row >= rowCount) {
               row = 0;
            }
               jTable1.getSelectionModel().setSelectionInterval(row, row);
               jTable1.getColumnModel().getSelectionModel().setSelectionInterval(col, col);
               jTable1.editCellAt(row, col);
            if(col==3 && row==rowCount-1) {
               addNewRow();
               jTable1.scrollRectToVisible(jTable1.getCellRect(rowCount,0, true)); 
            }
    
        }
    }
    

    初始化InputMap & ActionMap

    jTable1.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), "Action.NextCell");
    jTable1.getActionMap().put("Action.NextCell", new NextCellActioin());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-31
      • 2014-06-12
      • 2021-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多