2013-11-14 41 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

相關問題