2013-11-14 40 views
1

我有一个使用JComboBox作为单元格编辑器的自定义TableModel的自定义JTable。 ComboBox也有一个自定义ComboBoxModel ComboBox模型包含多个字段,这些字段将用于更新JTable后面的数据并随后更新数据库。JComboBox作为带有Overriden的Jtable CellEditor stopCellEditing修改错误的表格单元格

以下是显示我遇到的问题的简单示例。重现步骤:

  1. 单击一个细胞
  2. 从ComboBox中选择下拉列表
  3. 点击不同的细胞
  4. 点击后面的第一个选择的小区上

第二个单元格将获得第一个单元格的值。

这是怎么发生的?为什么ComboBox模型在stopCellEditing存在之前更改?

import javax.swing.DefaultCellEditor; 
import javax.swing.DefaultComboBoxModel; 
import javax.swing.JComboBox; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTabbedPane; 
import javax.swing.JTable; 
import javax.swing.table.DefaultTableModel; 

public class TestComboCellEditor { 

    public static void main(String[] args) { 

     TestComboCellEditor test = new TestComboCellEditor(); 
     test.go(); 
    } 

    public void go() { 

     //create the frame 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     // create and add a tabbed pane to the frame 
     JTabbedPane tabbedPane = new JTabbedPane(); 
     frame.getContentPane().add(tabbedPane); 
     //create a table and add it to a scroll pane in a new tab 
     final JTable table = new JTable(new DefaultTableModel(new Object[]{"A", "B"}, 5)); 
     JScrollPane scrollPane = new JScrollPane(table); 
     tabbedPane.addTab("test", scrollPane); 

     // create a simple JComboBox and set is as table cell editor on column A 
     Object[] comboElements = {"aaaaa1", "aaaaaa2", "b"}; 
     final JComboBox comboBox = new JComboBox(comboElements); 
     comboBox.setEditable(true); 
     table.getColumn("A").setCellEditor(new DefaultCellEditor(comboBox) { 
      @Override 
      public boolean stopCellEditing() { 
       if (comboBox.isEditable()) { 
        DefaultComboBoxModel comboModel = (DefaultComboBoxModel) comboBox.getModel(); 
        String selectedItem = (String) comboModel.getSelectedItem(); 
        int selectedIndex = comboModel.getIndexOf(selectedItem); 
        if (!(selectedIndex == -1)) { 
         // the selected item exists as an Option inside the ComboBox 
         DefaultTableModel tableModel = (DefaultTableModel) table.getModel(); 
         int selectedRow = table.getSelectedRow(); 
         int selectedColumn = table.getSelectedColumn(); 
         tableModel.setValueAt(selectedItem, selectedRow, selectedColumn); 
        } else if (selectedItem != null) { 
         // missing code - adding new info to a custom JComboBox model and to alter info inside a custom table model 
        } 
       } 
       return super.stopCellEditing(); 
      } 
     }); 

     // pack and show frame 
     frame.pack(); 
     frame.setVisible(true); 

    } 
} 
+0

执行无效:编辑**不能**更改视图/模型调用它 - 它的唯一责任是通知编辑完成并保持编辑值(为其客户端访问) – kleopatra

+0

我的第一次尝试是这样的:http://stackoverflow.com/questions/19938204/return-the-focus-to-jcombobox- jtable-after-showoptiondialog/19938451#19938451但遇到其他问题,所以我被推荐去这种方式。我一直在寻找最佳实践来实现我想要的东西,但找不到要使用的东西。如果你可以用一个例子来指向一个链接,它会很棒。 –

回答

0

好的,我做了一些改变,我想我有些工作。如果这不是最佳做法,并且您得到了更好的实施,请发布答案。

编辑:不要按照下面的例子!根据kleopatra的评论,这是一个错误的实施。我在这里离开它,所以你知道如何不是来做到这一点。

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.DefaultCellEditor; 
import javax.swing.DefaultComboBoxModel; 
import javax.swing.JComboBox; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTabbedPane; 
import javax.swing.JTable; 
import javax.swing.table.DefaultTableModel; 

public class TestComboCellEditor { 

    public static void main(String[] args) { 

     TestComboCellEditor test = new TestComboCellEditor(); 
     test.go(); 
    } 

    public void go() { 

     //create the frame 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     // create and add a tabbed pane to the frame 
     JTabbedPane tabbedPane = new JTabbedPane(); 
     frame.getContentPane().add(tabbedPane); 
     //create a table and add it to a scroll pane in a new tab 
     final JTable table = new JTable(new DefaultTableModel(new Object[]{"A", "B"}, 5)); 
     JScrollPane scrollPane = new JScrollPane(table); 
     tabbedPane.addTab("test", scrollPane); 

     // create a simple JComboBox and set is as table cell editor on column A 
     Object[] comboElements = {"aaaaa1", "aaaaaa2", "b"}; 
     final JComboBox comboBox = new JComboBox(comboElements); 
     comboBox.setEditable(true); 
     table.getColumn("A").setCellEditor(new DefaultCellEditor(comboBox) { 
      @Override 
      public boolean stopCellEditing() { 
       if (comboBox.isEditable()) { 
        DefaultComboBoxModel comboModel = (DefaultComboBoxModel) comboBox.getModel(); 
        String selectedItem = (String) comboModel.getSelectedItem(); 
        int selectedIndex = comboModel.getIndexOf(selectedItem); 
        if (!(selectedIndex == -1)) { 
         comboBox.actionPerformed(new ActionEvent(this, selectedIndex, "blabla")); 
        } else if (selectedItem != null) { 
         // missing code - adding new info to a custom JComboBox model and to alter info inside a custom table model 
        } 
       } 
       return super.stopCellEditing(); 
      } 
     }); 

     comboBox.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       // the selected item exists as an Option inside the ComboBox 
       if (e.getActionCommand().equals("blabla")) { 
        DefaultComboBoxModel comboModel = (DefaultComboBoxModel) comboBox.getModel(); 
        String selectedItem = (String) comboModel.getSelectedItem(); 
        DefaultTableModel tableModel = (DefaultTableModel) table.getModel(); 
        int selectedRow = table.getSelectedRow(); 
        int selectedColumn = table.getSelectedColumn(); 
        tableModel.setValueAt(selectedItem, selectedRow, selectedColumn); 
       } 
      } 
     }); 

     // pack and show frame 
     frame.pack(); 
     frame.setVisible(true); 

    } 
} 
+0

不,这是不对的 - **不要在编辑器和监听器中干涉JTable内部更新。 – kleopatra

+0

感谢提示。编辑完成后,我应该从哪里进行更新? –

+0

我仍然不明白为什么这里会帮助你的_real_问题 - 你要么默默地添加新的项目(对组合模型),而是使用它作为表模型,或者不要让用户再次选择,对? – kleopatra

4

这里是保持所有的代码编辑器的方法:

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.table.*; 

public class TestComboCellEditor { 

    public static void main(String[] args) { 

     TestComboCellEditor test = new TestComboCellEditor(); 
     test.go(); 
    } 

    public void go() { 

     //create the frame 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     // create and add a tabbed pane to the frame 
     JTabbedPane tabbedPane = new JTabbedPane(); 
     frame.getContentPane().add(tabbedPane); 
     //create a table and add it to a scroll pane in a new tab 
     final JTable table = new JTable(new DefaultTableModel(new Object[]{"A", "B"}, 5)); 
     JScrollPane scrollPane = new JScrollPane(table); 
     tabbedPane.addTab("test", scrollPane); 

     // create a simple JComboBox and set is as table cell editor on column A 
     Object[] comboElements = {"aaaaa1", "aaaaaa2", "b"}; 
     final JComboBox comboBox = new JComboBox(comboElements); 
     comboBox.setEditable(true); 
     table.getColumn("A").setCellEditor(new DefaultCellEditor(comboBox) 
     { 
      private Object originalValue; 

      @Override 
      public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) 
      { 
       originalValue = value; 
       return super.getTableCellEditorComponent(table, value, isSelected, row, column); 
      } 

      @Override 
      public boolean stopCellEditing() 
      { 
       JComboBox comboBox = (JComboBox)getComponent(); 
       DefaultComboBoxModel comboModel = (DefaultComboBoxModel) comboBox.getModel(); 
       Object editingValue = getCellEditorValue(); 

       // Needed because your TableModel is empty 

       if (editingValue == null) 
        return super.stopCellEditing(); 

       int selectedIndex = comboModel.getIndexOf(editingValue); 

       // Selecting item from model 

       if (! (selectedIndex == -1)) 
        return super.stopCellEditing(); 

       // Confirm addition of new value 

       int result = JOptionPane.showConfirmDialog(
        comboBox.getParent(), 
        "Add (" + editingValue + ") to table?", 
        "Update Model", 
        JOptionPane.YES_NO_OPTION); 

       if (result == JOptionPane.YES_OPTION) 
       { 
        comboBox.addItem(editingValue); 
        return super.stopCellEditing(); 
       } 
       else 
       { 
        comboBox.removeItem(editingValue); 
        comboBox.setSelectedItem(originalValue); 
        return false; 
       } 
      } 
     }); 

     // pack and show frame 
     frame.pack(); 
     frame.setVisible(true); 

    } 
} 
+1

这是近(到目前为止+1!) - 除了a)(猜测一点)当需求似乎是继续与编辑b)处理复杂的对象重置原始值。如果没有else块中的setSelectedItem(original),选项窗格会出现两次:罪魁祸首是用奇怪的UI /组合行为触发与“comboBoxEdited”相关的假动作事件。 – kleopatra

+1

我并不是真的想要所有代码编辑。我只是这样试过,因为我找不到更好的解决方案。我正在寻找的是一个很好的练习,它将使代码易于维护。我目前正在尝试使用自定义渲染器的解决方案,以便只使用cellEditor中的对话框(如您所建议的)从自定义模型中提取要显示的信息。这样当ComboBox将使用JTableModel所持有的相同数据结构并在您选择它时直接传递它。 JTable将使用类似的渲染器。让我知道你对此的看法。 –

+0

我想我不明白你的要求。我回答了你原来的问题。 – camickr

相关问题