我创建了一个包含“人员”列表的JTable
。一个人可以始终包含另一个人(或可能本身)。因此,用户可以单击列,然后显示JComboBox
。该JComboBox包含JTable的所有人员。
用户完成JTable的编辑后,可以单击JButton
“保存”。在此示例中,它将仅将TableModel的值打印到控制台。
问题:
最后的更改未“转移”到TableModel。
例如。用户为每一行选择Kim人。对于他来说,它看起来不错,但是如果单击该按钮,您将看到最后一行的“ Person”列的值仍然是John。
当用户单击另一列时,在第三列中更改了人员,然后单击“按钮”,则输出正确。
我认为我缺少了一些东西,但我不知道问题出在哪里。
对于JTable,我使用了本教程: https://www.codejava.net/java-se/swing/how-to-create-jcombobox-cell-editor-for-jtable
这是我的代码:
public class Person {
private String name;
private Person person;
private String job;
public Person(String name, String job) {
this.name = name;
this.job = job;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
}
public class PersonTable extends JTable {
private PersonTableModel tableModel;
public PersonTable(List<Person> listPerson) {
tableModel = new PersonTableModel(listPerson);
this.setModel(tableModel);
this.setDefaultRenderer(Person.class, new PersonCellRenderer());
this.setDefaultEditor(Person.class, new PersonCellEditor(listPerson));
}
public Set<Person> getAllPersons() {
Set<Person> set = new HashSet<Person>();
for (int i = 0; i < tableModel.getRowCount(); i++) {
set.add(tableModel.getPerson(i));
}
return set;
}
}
public class PersonCellEditor extends AbstractCellEditor
implements TableCellEditor, ActionListener {
private Person Person;
private List<Person> listPerson;
public PersonCellEditor(List<Person> listPerson) {
this.listPerson = listPerson;
}
@Override
public Object getCellEditorValue() {
return this.Person;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
if (value instanceof Person) {
this.Person = (Person) value;
}
JComboBox<Person> comboPerson = new JComboBox<Person>();
comboPerson.setRenderer(new PersonComboBoxRenderer());
for (Person aPerson : listPerson) {
comboPerson.addItem(aPerson);
}
comboPerson.setSelectedItem(Person);
comboPerson.addActionListener(this);
if (isSelected) {
comboPerson.setBackground(table.getSelectionBackground());
} else {
comboPerson.setBackground(table.getSelectionForeground());
}
return comboPerson;
}
@Override
public void actionPerformed(ActionEvent event) {
JComboBox<Person> comboPerson = (JComboBox<Person>) event.getSource();
this.Person = (Person) comboPerson.getSelectedItem();
}
}
public class PersonCellRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof Person) {
Person Person = (Person) value;
setText(Person.getName());
}
if (isSelected) {
setBackground(table.getSelectionBackground());
} else {
setBackground(table.getSelectionForeground());
}
return this;
}
}
public class PersonTableModel extends AbstractTableModel {
private String[] columnNames = {"No.", "Name", "Person", "Job"};
private List<Person> listPerson = new ArrayList<>();
public PersonTableModel(List<Person> listPerson) {
this.listPerson.addAll(listPerson);
}
@Override
public int getColumnCount() {
return columnNames.length;
}
public String getColumnName(int column) {
return columnNames[column];
}
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
@Override
public int getRowCount() {
return listPerson.size();
}
@Override
public void setValueAt(Object value, int rowIndex, int columnIndex) {
Person person = listPerson.get(rowIndex);
switch (columnIndex) {
case 1:
person.setName((String) value);
break;
case 2:
person.setPerson((Person) value);
break;
case 3:
person.setJob((String) value);
break;
}
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object returnValue = null;
Person person = listPerson.get(rowIndex);
switch (columnIndex) {
case 0:
returnValue = rowIndex + 1;
break;
case 1:
returnValue = person.getName();
break;
case 2:
returnValue = person.getPerson();
break;
case 3:
returnValue = person.getJob();
break;
}
return returnValue;
}
public Person getPerson(int row) {
return listPerson.get(row);
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex > 0;
}
}
public class PersonComboBoxRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if(value instanceof Person) {
Person p = (Person) value;
setText(p.getName());
}
return this;
}
}
public class JComboBoxTableCellEditorExample extends JFrame {
public JComboBoxTableCellEditorExample() {
super("JComboBox Cell Editor for JTable Demo");
List<Person> listPerson = new ArrayList<>();
Person p1 = new Person("John", "Developer");
Person p2 = new Person("Kim", "Designer");
Person p3 = new Person("Peter", "Manager");
p1.setPerson(p2);
p2.setPerson(p3);
p3.setPerson(p1);
listPerson.add(p1);
listPerson.add(p2);
listPerson.add(p3);
PersonTable table = new PersonTable(listPerson);
JScrollPane scrollpane = new JScrollPane(table);
scrollpane.setPreferredSize(new Dimension(400, 200));
add(scrollpane, BorderLayout.CENTER);
JButton buttonSave = new JButton("Save");
buttonSave.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (Person p : table.getAllPersons()) {
System.out.println(p.getName() + " --> " + p.getPerson().getName());
}
}
});
add(buttonSave, BorderLayout.PAGE_END);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
ex.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new JComboBoxTableCellEditorExample();
}
});
}
}
答案 0 :(得分:2)
我已经测试了您的代码,并应用了camickr here解释的解决方案来解决问题
在此entry中,camickr自己解释了您面临的问题。让我引用摘录
在JTable中编辑单元格时,表不知道用户何时 完成单元格的编辑。因此,用户有责任 告诉表格何时停止编辑。
通常通过以下方式完成
:
- 使用Enter键
- 跳至下一个单元格
- 点击另一个单元格 用鼠标
如果您编辑第三行Person [column 2]并立即按下“保存”按钮,则JTable不会检测到您已经完成了对该单元格的编辑。那就是你得到的原因
Kim --> Kim
John --> Kim
Peter --> John
camickr提供的一种解决方案是,当您检测到已按下“保存”按钮时,将强制停止编辑。只需更改按钮声明
JButton buttonSave = new JButton("Save");
buttonSave.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (table.isEditing()) {
table.getCellEditor().stopCellEditing();
}
for (Person p : table.getAllPersons()) {
System.out.println(p.getName() + " --> " + p.getPerson().getName());
}
}
});
现在您应该获得所需的结果。
请注意,如果稍稍更改了PersonTable类,而在方法getAllPersons
中替换了Set by List,则会获得有序结果,从而提高了控制台的可读性。
public class PersonTable extends JTable {
private PersonTableModel tableModel;
public PersonTable(List<Person> listPerson) {
tableModel = new PersonTableModel(listPerson);
setModel(tableModel);
setDefaultRenderer(Person.class, new PersonCellRenderer());
setDefaultEditor(Person.class, new PersonCellEditor(listPerson));
}
public List<Person> getAllPersons() {
List<Person> set = new ArrayList<Person>();
for (int i = 0; i < tableModel.getRowCount(); i++) {
set.add(tableModel.getPerson(i));
}
return set;
}
}
使用List进行控制台输出,无需更改
John --> Kim
Kim --> Peter
Peter --> John