2013-10-23 12 views
0

我有一個JComboBoxes列的GUI,其中每個列都是唯一的。我真的不明白我在做什麼,所以最近在一個特別長的障礙序列中,當編輯一個盒子時,它不顯示新選擇的值。如果再次選中該框,單元格中的值將更新爲之前選擇的值,因此推測這只是表/渲染器未更新的問題。在JTable中,當編輯單元格獨特的JComboBoxes時更新顯示的項目

我懷疑我可能需要在某個地方爲每個組合框註冊一個偵聽器,但我不知道哪一類偵聽器在哪個類上。

下面是說明作爲簡潔的,因爲它代表我會管理設計的SSCCE:

import java.awt.Component; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 

import javax.swing.DefaultCellEditor; 
import javax.swing.JComboBox; 
import javax.swing.JFrame; 
import javax.swing.JTable; 
import javax.swing.border.EmptyBorder; 
import javax.swing.event.TableModelListener; 
import javax.swing.table.TableCellEditor; 
import javax.swing.table.TableCellRenderer; 
import javax.swing.table.TableColumn; 
import javax.swing.table.TableModel; 

@SuppressWarnings("serial") 
public class ComboBoxTableGUI extends JFrame { 

    public List<SampleCollection> masterList; 

    public static void main(String[] args) { 
     new ComboBoxTableGUI(); 
    } 

    public ComboBoxTableGUI() { 
     // create a collection of 10 collections, each with 1-10 Strings 
     masterList = new ArrayList<SampleCollection>(); 
     Random rnd = new Random(); 
     for (int i = 0; i < 10; i++) { 
      SampleCollection sc = new SampleCollection("Option " + i + ":"); 
      int choices = rnd.nextInt(9) + 1; 
      for (int j = 0; j < choices; j++) { 
       sc.choices.add("Choice " + j); 
      } 
      sc.selectedChoice = sc.choices.get(0); 
      masterList.add(sc); 
     } 

     this.setSize(500, 500); 
     this.setLocationRelativeTo(null); 

     TableModel optionTableModel = new OptionTableModel(); 
     JTableWithCustomEditors optionsTable = new JTableWithCustomEditors(optionTableModel); 

     this.add(optionsTable); 

     TableColumn optionCol = optionsTable.getColumnModel().getColumn(1); 
     optionCol.setCellRenderer(new CustomComboBoxRenderer()); 

     List<TableCellEditor> editors = new ArrayList<TableCellEditor>(); 
     for (SampleCollection collection : masterList) { 
      JComboBox<String> cb = new JComboBox<String>(); 
      for (String choice : collection.choices) { 
       cb.addItem(choice); 
      } 
      DefaultCellEditor editor = new DefaultCellEditor(cb); 
      editors.add(editor); 
     } 
     optionsTable.editors = editors; 

     this.setVisible(true); 
    } 

    public class SampleCollection { 
     public String name, selectedChoice; 
     public List<String> choices; 

     public SampleCollection(String name) { 
      this.name = name; 
      this.choices = new ArrayList<String>(); 
     } 
    } 

    public class JTableWithCustomEditors extends JTable { 
     public List<TableCellEditor> editors; 

     public JTableWithCustomEditors(TableModel model) { 
      super(model); // lol 
     } 

     @Override 
     public TableCellEditor getCellEditor(int row, int column) { 
      if (column == 1) 
       return editors.get(row); 
      else 
       return super.getCellEditor(row, column); 
     } 
    } 

    class CustomComboBoxRenderer extends JComboBox<String> implements 
      TableCellRenderer { 
     public CustomComboBoxRenderer() { 
      setBorder(new EmptyBorder(0, 0, 0, 0)); 
     } 

     public Component getTableCellRendererComponent(JTable table, 
       Object value, boolean isSelected, boolean hasFocus, int row, 
       int column) { 

      removeAllItems(); 
      addItem(((SampleCollection) value).selectedChoice); 

      this.setSelectedIndex(0); 
      return this; 
     } 
    } 

    public class OptionTableModel implements TableModel { 
     private List<TableModelListener> listeners; 

     public OptionTableModel() { 
      listeners = new ArrayList<TableModelListener>(); 
     } 

     @Override 
     public void addTableModelListener(TableModelListener l) { 
      listeners.add(l); 
     } 

     @Override 
     public Class<?> getColumnClass(int columnIndex) { 
      if (columnIndex == 1) 
       return SampleCollection.class; 
      else 
       return String.class; 
     } 

     @Override 
     public int getColumnCount() { 
      return 2; 
     } 

     @Override 
     public String getColumnName(int columnIndex) { 
      if (columnIndex == 0) 
       return "Name"; 
      else 
       return "Selection"; 
     } 

     @Override 
     public int getRowCount() { 
      if (masterList == null) 
       return 0; 
      else 
       return masterList.size(); 
     } 

     @Override 
     public Object getValueAt(int rowIndex, int columnIndex) { 
      if (columnIndex == 0) 
       return masterList.get(rowIndex).name; 
      else 
       return masterList.get(rowIndex);// also tried .choices 
     } 

     @Override 
     public boolean isCellEditable(int rowIndex, int columnIndex) { 
      if (columnIndex == 1) 
       return true; 
      else 
       return false; 
     } 

     @Override 
     public void removeTableModelListener(TableModelListener l) { 
      listeners.remove(l); 
     } 

     @Override 
     public void setValueAt(Object aValue, int rowIndex, int columnIndex) { 
      // the values are grabbed when the user clicks an OK button, right 
      // now I just need to get it rendering 
     } 
    } 
} 

回答

1

你TableModel的實現是不正確。

首先,數據應該存儲在模型中而不是作爲類中的實例變量。

setValueAt(...)方法應更新您的列表中的數據,然後應調用fireTableCellUpdated(...)這將告訴該表的數據已更改,因此該單元格可以重新繪製。

+0

數據生活在遙遠的地方,當TableModel顯示時,'TableModel'確實獲得了對相應'List 的引用;我只想爲這個例子提供儘可能少的方法,參數和字段。 您可以詳細說明調用'fireTableCellUpdated()'嗎? –

+0

已解決:添加到'setValueAt(...)'行'masterList.get(rowIndex).selectedChoice =(String)aValue;'和框更新正確。 我對這個所謂的'fireWhateverThing'感到困惑,因爲它在'AbstractTableModel'中,我沒有使用它。 –

+0

@ Mr.Wallet,您應該擴展AbstractTableModel,以便調用相應的fireXXX方法。 「數據生活很遙遠,TableModel確實得到了一個參考,這不是正確的設計。數據應該駐留在TableModel中。所有更新數據的方法都應該是模型的一部分。這是所有Swing組件使用的MVC設計的基礎。不要做愚蠢的事情,因爲你認爲它更容易。從長遠來看,這並不容易,我相信你會回到論壇上提問,因爲你目前的設計。 – camickr

相關問題