[英]Editing JTable cells after being cloned
我正在為一個工作項目工作,但遇到了一個異常問題。 我有一個JTable,用戶可以在其中填充數據。 在我的實際代碼中,有一個“添加行”按鈕,該按鈕使用戶可以填寫一些GUI,而該信息將生成該行。
此功能的另一個重要功能是用於克隆行的按鈕。 由於添加一行的過程可能非常耗時(有許多字段需要填寫),如果用戶只需要添加一個新行,但其中的一個單元格不同,那么他可以使用按鈕克隆該單元格。
此克隆按鈕按預期工作,但是存在一個相當奇怪的問題。 克隆一行后,我注意到當我嘗試更改已克隆的任何單元格的內容時,會出現意外結果。 例如,如果我將一個單元格的內容更改為“ 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);
}
}
聽起來您正在重用相同的引用,而不是在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)創建一個類似於上面的新Vector,為Vector中的任何基於Class的對象重新創建它們,因為當前您正在處理指針。
我很難說#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();
使它工作。
克隆是此處的關鍵字。 您沒有克隆數據。 您只是將引用從一個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(...)方法時觸發適當的方法。
編輯:
是的,使用克隆確實可以,但是您需要克隆Vector而不是Vector中的每個項目:
//dtm.insertRow(insertPoint, targetRow);
dtm.insertRow(insertPoint, (Vector)targetRow.clone());
要么
dtm.insertRow(insertPoint, new Vector(targetRow));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.