JComboBox并不总是将值保存到TableModel

时间:2019-01-04 09:35:36

标签: java swing jtable jcombobox

我创建了一个包含“人员”列表的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();
            }
        });
    }

}

1 个答案:

答案 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