使用all(jComboBox,JTextField,jFileChooser)作为表编辑器会覆盖引用

在下面的代码中,对于同一个表的各行,我试图将Editable comboBox设置为第一行的编辑器(以便用户可以从可用选项中进行选择或键入自己的选项),第二行的文件选择器和默认值textFiled用于其余行。

问题:以及重现它的步骤:

1-运行代码, 2-单击第二行并选择一个文件夹(行变为黄色) 3-现在单击第一行选择电影类型(只需单击,无需键入任何内容或选择) 4-现在再次点击第二行(文件夹选择)

你会看到这行的内容会被复制到第一行吗?!

我知道有很多事情我做得不对,也许处理不是线程安全的波动,处理引用等等。 我想知道你们是否可以帮助我解决这个问题,并将此代码转化为可靠的代码。

用户进行选择前的程序输出

按照以上步骤操作后:

在此处输入图像描述

import java.awt.Color; import java.awt.Component; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.File; import javax.swing.DefaultCellEditor; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.table.TableModel; public class CCellEditor extends DefaultCellEditor { private JTable m_Table = null; public CCellEditor(JFrame parentFrame, JTable table) { super(new JTextField()); super.setClickCountToStart(1); m_Table = table; } public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, final int row, int column){ if(row==0) // comBoBox for First row { Object[] objectArray = {"3D","2D"}; JComboBox comboBox = new JComboBox(objectArray); comboBox.setEditable(true); comboBox.setSelectedItem(value); ItemListener itemListener = new ItemListener() { public void itemStateChanged(ItemEvent e) { if(e.getStateChange() == ItemEvent.SELECTED) { if(null != m_Table.getCellEditor()){ m_Table.getCellEditor().stopCellEditing(); } m_Table.setValueAt(e.getItem(), row, 1); } } }; comboBox.addItemListener(itemListener); PopupMenuListener popMenuEvent = new PopupMenuListener() { public void popupMenuWillBecomeVisible(PopupMenuEvent e) { } public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { String sValue = (String)m_Table.getValueAt(row, 1); if(null != m_Table.getCellEditor()){ m_Table.getCellEditor().stopCellEditing(); } m_Table.setValueAt(sValue, row, 1); } public void popupMenuCanceled(PopupMenuEvent e) { } }; comboBox.addPopupMenuListener(popMenuEvent); return comboBox; } else if(row==1) // fileChooser for Second row { JFileChooser fileChooser; fileChooser = new JFileChooser("c:\\"); fileChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); fileChooser.setVisible(true); int returnVal = fileChooser.showOpenDialog(null); JTextField textField = (JTextField)super.getTableCellEditorComponent(table, value, isSelected, row, column); textField.setBackground(Color.yellow); if (returnVal == JFileChooser.APPROVE_OPTION) { File m_fFirmware= fileChooser.getSelectedFile(); textField.setText(m_fFirmware.getPath()); return textField; }else { return textField; } } // for any other rows JTextField textField = (JTextField)super.getTableCellEditorComponent(table, value, isSelected, row, column); return textField; } public static void main(String[] a) { JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); String[] columnTitles = { "Name", "Value"}; Object[][] dataEntries = { { "Movie Type:", "3D" }, {"Folder:","C:"}, {"# of Movies requested:","5"}}; TableModel model = new EditableTableModel(columnTitles, dataEntries); JTable table = new JTable(model); table.createDefaultColumnsFromModel(); table.setDefaultEditor(Object.class, new CCellEditor(frame, table)); frame.add(new JScrollPane(table)); frame.setSize(300, 200); frame.setVisible(true); } } 

这是EditableTableModel类:

 import javax.swing.table.AbstractTableModel; class EditableTableModel extends AbstractTableModel { String[] columnTitles; Object[][] dataEntries; int rowCount; public EditableTableModel(String[] columnTitles, Object[][] dataEntries) { this.columnTitles = columnTitles; this.dataEntries = dataEntries; } public int getRowCount() { return dataEntries.length; } public int getColumnCount() { return columnTitles.length; } public Object getValueAt(int row, int column) { return dataEntries[row][column]; } public String getColumnName(int column) { return columnTitles[column]; } public Class getColumnClass(int column) { return getValueAt(0, column).getClass(); } public boolean isCellEditable(int row, int column) { return true; } public void setValueAt(Object value, int row, int column) { dataEntries[row][column] = value; } } 

我必须承认我花了一段时间,但我发现了这个问题。 您没有重写DefaultCellEditor.getCellEditorValue()函数,这对您的实现很重要。 当正在编辑的单元格失去焦点或其他导致编辑完成的任何其他内容时,将调用此函数。 无论如何,在你的情况下,它只是从最后一个默认的TableCellEditor(来自DefaultCellEditor)获取最终值。 这就是第一行不断被最后编辑的单元格值替换的原因。

这是一种解决问题的方法:

  1. 创建对comboBox的全局引用。
  2. 如果最后编辑的项目是第二行,则覆盖getCellEditorValue()并返回comboBox.getSelectedItem() 。 否则,只返回super.getCellEditorValue()

这将解决您当前的问题,但您的代码可以使用很多改进。

初步检查建议让模型通知其对更改的收听视图:

 public void setValueAt(Object value, int row, int column) { dataEntries[row][column] = value; fireTableCellUpdated(row, column); } 

另请参阅初始线程 ,并考虑其中一个默认目录。

 fileChooser = new JFileChooser(System.getProperty("user.dir")); fileChooser = new JFileChooser(System.getProperty("user.home"));