【问题标题】:Controlled editing of a row selection in JTableJTable 中行选择的受控编辑
【发布时间】:2012-02-27 15:52:27
【问题描述】:

我有一个 JTable 显示来自 SQL 数据库的行。该表相对较小(只有 4 列,最多 1000 行)。

我想让用户有机会编辑表格中的任何单元格,但希望避免对其进行过多限制,以至于他们必须使用编辑对话框(这使得错误检查和验证更容易,但不太直观)

我尝试了几种使用 JTable 的 valueChanged 方法控制编辑选择的不同方法,但运气不佳。

我希望在编辑结束时编辑每一行并将其写入数据库。我希望一旦单击单元格开始编辑该行,在用户完成编辑该行之前不能选择其他行(其他行显示为灰色)。编辑每个单元格并按 Enter 后,编辑选择应跳转到同一行的下一列。

谁能指点我如何做到这一点?

//  Create table with database data
   table = new JTable(new DefaultTableModel(data, columnNames)) {
        public Class getColumnClass(int column) {
            for (int row = 0; row < getRowCount(); row++) {
                Object o = getValueAt(row, column);
                if (o != null){
                    return o.getClass();
                }
            }
            return Object.class;
        }

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

        @Override
        public boolean editCellAt(int row, int column) {
            boolean ans = super.editCellAt(row, column);
            if (ans) { 
                Component editor = table.getEditorComponent();
                editor.requestFocusInWindow();
            }
            return ans;
        }

        @Override
        public void valueChanged(ListSelectionEvent source) {
            super.valueChanged(source);
            if (table!=null)
                table.changeSelection(getSelectedRow(), getSelectedColumn()+1, false, false);
        }

    };

编辑 - 带有表格指针的自定义单元格编辑器似乎是一个开始

public class ExchangeTableCellEditor  extends AbstractCellEditor implements TableCellEditor {

private JTable table;

JComponent component = new JTextField();

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

public boolean stopCellEditing() {
    boolean ans = super.stopCellEditing();
    //now we want to increment the cell count
    table.editCellAt(table.getSelectedRow(), table.getSelectedColumn()+1);
    return ans;
}

@Override
public void cancelCellEditing() {
    //do nothing... must accept cell changes 
}

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

@Override
public Component getTableCellEditorComponent(JTable arg0, Object value,
        boolean arg2, int arg3, int arg4) {
    ((JTextField)component).setText((String)value);
    return component;
}

}

【问题讨论】:

  • 请编辑您的问题,在sscce 中包含您遇到的任何问题。
  • 编辑了一个示例,说明我在编辑时如何尝试更改选择。谢谢
  • 不要让 CellEditor 变得聪明——永远不会!这里特别是指重新开始编辑,这会混淆所有内部更新......
  • 顺便说一句,实现无效 - 它必须在编辑因编辑器内部原因终止时通知其侦听器(例如,当用户提交值时)参见 DefaultCellEditor 源代码示例

标签: java swing jtable


【解决方案1】:

default renderer and editor 通常适用于大多数数据类型,但您可以根据需要定义自定义 rendererseditors

附录:我不熟悉您的片段中显示的方法。相反,在您的模型中注册一个TableModelListener,如下所示,并以任何保证的粒度更新数据库。另见How to Use Tables: Listening for Data Changes

附录:@kleopatra 关于您的TableCellEditor 是正确的。通知侦听器的一种方便方法是调用超级实现,如here 所示。注意delegate 调用fireEditingStopped()

/** @see https://stackoverflow.com/questions/9155596 */
public class NewJavaGUI extends JPanel {

    private final JTable table;

    public NewJavaGUI() {
        String[] colNames = {"C1", "C2", "C3"};
        DefaultTableModel model = new DefaultTableModel(colNames, 0) {

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

            @Override
            public Class getColumnClass(int col) {
                // return your actual type tokens
                return getValueAt(0, col).getClass();
            }
        };
        // Add data; note auto-boxing
        model.addRow(new Object[]{"A1", "A2", 42});
        model.addRow(new Object[]{"B1", "B2", 42d});
        model.addTableModelListener(new TableModelListener() {

            @Override
            public void tableChanged(TableModelEvent e) {
                // DML as indicated
            }
        });
        table = new JTable(model);
        this.add(table);
    }

    private void display() {
        JFrame f = new JFrame("NewJavaGUI");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new NewJavaGUI().display();
            }
        });
    }
}

【讨论】:

  • 感谢您的回答 - 链接和代码足以让我们朝着正确的方向前进。已使用似乎启动解决方案的自定义单元格编辑器编辑了我的问题。
  • 星期一是吹毛求疵的一天 :-) 模型规则 - 不要在视图中重新/实现其任何 in 方法,尤其是不能无条件地允许编辑 - 即使在示例中,新手也容易记住那些...
  • @kleopatra:非常棒的选择;我的粗心大意;更新。谢谢!
  • 坚持让我仍然不满意:该规则适用于模型的 所有 方法。视图不能事后猜测模型的意图(如果模型故意返回尽可能广泛的类型,因为它允许并且实际上包含各种图标、字符串、数字......)?虽然这只是一个例子——我们永远不会在任何现实世界的环境中编码——错误的位置正在蔓延,见 f.i stackoverflow.com/questions/9239270/…
  • @kleopatra: 哦,我的粗心更多;感谢您抽出宝贵时间审阅和评论。
【解决方案2】:

您提到的行为可以通过强制您的表格重新开始编辑来实现。

首先确保您现在是您的行和列,并添加您自己的从 AbstractCellEditor 扩展的 tablecelleditor 然后将其添加到您的 stopCellEditing 方法中:

EventQueue.invokeLater(new Runnable()
    {

      public void run()
      {
        yourTable.editCellAt( yourRow, yourColumn+1);
      }
    });

【讨论】:

  • -1 让编辑器干预表的状态是错误的——唯一的工作是允许编辑一个值并在它准备好时向其侦听器报告。然后 listener(主要是表本身)将获取新值并使用它做需要的事情
  • 编辑器不影响状态。它只是对桌子说重新开始编辑。
  • 哪个正在改变它的状态 ;-) 那不是编辑的工作。
猜你喜欢
  • 2016-08-29
  • 1970-01-01
  • 1970-01-01
  • 2018-10-30
  • 2023-03-24
  • 2017-04-01
  • 2011-05-30
  • 2010-11-27
  • 2014-05-08
相关资源
最近更新 更多