【问题标题】:Editing JTable cells after being cloned克隆后编辑 JTable 单元格
【发布时间】:2016-04-15 18:20:45
【问题描述】:

我正在处理一个工作项目,但遇到了一个不寻常的问题。我有一个用户可以用数据填充的 JTable。在我的实际代码中,有一个“添加行”按钮,可以让用户填写一些 GUI,然后这些信息会生成行。

另一个重要功能是克隆行的按钮。由于添加行的过程可能非常耗时(需要填写许多字段),如果用户只需要添加一个具有 1 个不同单元格的新行,那么他可以使用按钮克隆该单元格。

这个克隆按钮按预期工作,但是有一个相当奇怪的问题。克隆一行后,我注意到当我尝试更改已克隆的任何单元格的内容时,会出现意想不到的结果。例如,如果我将一个单元格的内容更改为“Ryan”,那么其他单元格也可能会突然改变,如果我什至在更改一个单元格后单击一个单元格,我单击的单元格将自行更改。我很确定这个问题与我真的不知道要修复的克隆方法有关。

我创建了一个可验证的程序,因此您可以自己将其发送出去,看看我在说什么。只需使用克隆按钮几次,然后尝试更改单个单元格的内容并观察其他单元格中的结果..

我真的需要解决这个问题,但我不知道该怎么做,非常感谢您的帮助。

主类

package jtabletest;

public class JTableTestMain 

{

    public static void main(String args[]){

        JTableTest jTest = new JTableTest();
        jTest.createGUI();

    }

}

JTable 类

package jtabletest;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class JTableTest 

{

    protected static DefaultTableModel dtm = new DefaultTableModel();
    public static JTable tbl;


    public void createGUI(){

        final JFrame frame = new JFrame("JTable Test");
        JPanel mainPanel = new JPanel(new BorderLayout());
        JPanel panelNorth = new JPanel(new BorderLayout());
        JPanel panelSouth = new JPanel(new BorderLayout());
        JPanel buttonPanel = new JPanel();

        JButton cloneButton = new JButton("Clone");
        cloneButton.setPreferredSize(new Dimension(150,40));
        buttonPanel.add(cloneButton);

        JButton printButton = new JButton("Print");
        printButton.setPreferredSize(new Dimension(150,40));
        buttonPanel.add(printButton);

        tbl = new JTable();

        String header[] = new String[]{
                "Employee", "Pay-Rate", "Hours Worked"};


        dtm.setColumnIdentifiers(header);

        tbl.setModel(dtm);

        tbl.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

        for(int i = 0; i < header.length; i++){
            tbl.getColumnModel().getColumn(i).setPreferredWidth(200);
        }

        dtm.addRow(new Object[]{"Pete","$10.00","40"});
        dtm.addRow(new Object[]{"Bob","12.50","42"});
        dtm.addRow(new Object[]{"Jamar","$7.25,25"});

        cloneButton.addActionListener(new ActionListener(){

            public void actionPerformed(ActionEvent ae){

                int[] selectedRows = tbl.getSelectedRows();

                if(selectedRows.length>0){

                    @SuppressWarnings("rawtypes")
                    Vector data = dtm.getDataVector();

                    int insertPoint = selectedRows[selectedRows.length-1]+1;

                    for(int i = 0; i < selectedRows.length; i++){
                        @SuppressWarnings("rawtypes")
                        Vector targetRow = (Vector)data.elementAt(selectedRows[i]);

                        dtm.insertRow(insertPoint, targetRow);
                        insertPoint++;

                    }

                    dtm.fireTableDataChanged();

                }

            }

        });

        printButton.addActionListener(new ActionListener(){

            public void actionPerformed(ActionEvent ae){

                if(null != tbl.getCellEditor()){
                    tbl.getCellEditor().stopCellEditing();
                }

                for(int i = 0; i < tbl.getRowCount(); i++){
                    System.out.println(tbl.getValueAt(i, 0));
                    System.out.println(tbl.getValueAt(i, 1));
                    System.out.println(tbl.getValueAt(i, 2));
                }

            }

        });

        panelNorth.add(tbl,BorderLayout.NORTH);
        panelNorth.setPreferredSize(new Dimension(500,500));
        panelSouth.add(buttonPanel,BorderLayout.NORTH);
        mainPanel.add(panelNorth,BorderLayout.NORTH);
        mainPanel.add(panelSouth,BorderLayout.SOUTH);
        frame.add(mainPanel);
        frame.setVisible(true);
        frame.setSize(1900,600);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);



    }

}

【问题讨论】:

    标签: java swing jtable clone


    【解决方案1】:

    听起来您正在重用相同的引用,而不是在 clone 方法上复制新对象。我建议执行以下操作。

    1) 首先创建一个新的 Vector 看看是否可以解决问题,就像这样。

    for(int i = 0; i < selectedRows.length; i++){
      @SuppressWarnings("rawtypes")
      Vector targetRow = (Vector)data.elementAt(selectedRows[i]);
      Vector newVector = new Vector();
      for (int t = 0; t < targetRow.size(); t++) {
         newVector.add(targetRow.get(t));
      }
      dtm.insertRow(insertPoint, newVector);
      insertPoint++;
    }
    

    看看这是否能解决您的问题。如果是这样,你就完成了。如果没有,那么

    2) 创建一个类似于上面的新向量,为向量中的任何基于类的对象重新创建它们,因为您当前正在处理指针。

    我很难说#1 是否能解决您的问题,因为我不知道来自表格的 Vector 的内容,如果它是原语,您可能是安全的,否则您可能需要解决 # 2.

    【讨论】:

    • 我用您的测试程序#1 进行了验证,将解决您的问题。根本问题是您正在传递对 Vector 的引用并在多行上重用它。这是相同的基础数据。
    • 这个解决方案效果很好。非常感谢您的帮助,欢迎堆栈溢出!
    【解决方案2】:

    你的问题出在这一行:

    Vector targetRow = (Vector)data.elementAt(selectedRows[i]);
    

    你不是在创建一个副本,你是在创建一个新的引用,所以当你添加时

    dtm.insertRow(insertPoint, targetRow)
    

    您添加的行实际上是相同的,而不是先前选择的行的副本。

    你必须使用类似的东西

    Vector aux = (Vector)data.elementAt(selectedRows[i]);
    Vector targetRow = aux.clone();
    

    让它工作。

    【讨论】:

    • 该代码不起作用,当我尝试输入它时。Clone() 没有作为有效方法出现。
    • 好的,这是我的秘密,我尝试在将其设为 Vector 之前进行克隆
    • 没关系。自从您花时间回答以来,我仍然对您的回答投了赞成票:)
    【解决方案3】:

    克隆是这里的关键词。您没有克隆数据。您只是将引用从一个 Vector 复制到另一个。因此,由于每一行共享相同的引用,因此值出现在两行中。

    所以你需要实际克隆每个元素。

    代码类似于:

      Vector targetRow = (Vector)data.elementAt(selectedRows[i]);
      Vector clonedRow = new Vector(targetRow.size());
    
      for (Object object: targetRow)
      {
         clonedRow.addElement( object.clone() );
      }
    

    请注意,我以前从未使用过 clone(),所以您也许可以使用:

      Vector targetRow = (Vector)data.elementAt(selectedRows[i]);
      Vector clonedRow = targetRow.clone();
    

    但我不确定它是否只是克隆 Vector 而不是 Vector 中的元素。

    此外,您永远不会调用 firstTableDataChanged() 方法。这是 DefaultTableModle 在调用 insertRow(...) 方法时触发适当方法的工作。

    编辑:

    是的,使用克隆确实有效,但您需要克隆向量而不是向量中的每个项目:

    //dtm.insertRow(insertPoint, targetRow);
    dtm.insertRow(insertPoint, (Vector)targetRow.clone());
    

    dtm.insertRow(insertPoint, new Vector(targetRow));
    

    【讨论】:

    • 顶部代码不起作用。当我尝试使用最终的 object.clone 时,我收到一条错误消息,提示“来自对象类型的方法 clone() 不可见。
    • @jesric1029,是的,你是对的,正如我所说,我以前从未使用过 clone() :) 但是,第二种方法确实有效,但 Vector 确实实现了 clone(),所以你可以调用它直接地。见编辑。
    猜你喜欢
    • 2019-04-30
    • 1970-01-01
    • 2011-09-27
    • 2012-04-21
    • 2023-03-23
    • 1970-01-01
    • 2021-07-08
    • 2013-05-30
    • 1970-01-01
    相关资源
    最近更新 更多