2016-11-06 43 views
0

我得到一個JTable,其內容是類「item」的Vector。類項包含數字和字母數字字段以及適當的getter/setter,除了字段alt是字符串ArrayList。對於本專欄,我打算使用comboBox風格的渲染器和編輯器來選擇一個可用選項並顯示選項。 alt字段因行而異,這就是我所遇到的問題。我在這裏看到了很多這樣的渲染器的例子,但在所有例子中,每行的可用選項都是相同的。下面的代碼:在JTable中設置Combobox類型的渲染器/編輯器

public class item extends Vector { 

private int no, code; 
private String ....; 
private List<String> alt; 

@SuppressWarnings("unchecked") 
public item(int no, int code, ...., List alt) { 
    super(); 
    this.add(no); 
    this.add(code); 
    .... 
    this.add(alt); 
} 

public int getNo() { 
    return (int) this.get(0); 
} 

public void setNo(int no) { 
    this.no = no; 
} 

// other setter/getters... 

public void setAlt(List<String> alt) { 
    this.alt = alt; 
} 

@SuppressWarnings("unchecked") 
public List<String> getAlt() { 
    return (List<String>) this.get(6); 
} 

@SuppressWarnings("all") 
public Vector getAsVector() { 
    // ArrayList<Object> a= new ArrayList<Object>(); 
    Vector a = new Vector(7); 
    a.add(no); 
    a.add(sifra); 
    a.add(red1); 
    a.add(red2); 
    a.add(sastojci); 
    a.add(eanKod); 
    a.add(alt); 
    return a; 
} 

}

JTable中獲取必要的功能:

public Class getColumnClass(int ci){ 
    if (ci==6) return JComboBox.class; 
    else return String.class;  
} 


@Override 
public void setValueAt(Object value, int rowIndex, int columnIndex) { 
    item it = data.get(rowIndex); 

    switch (columnIndex) { 
    case 0: 
     it.setNo((int) value); 
     break; 
    case 1: 
     it.setCode((int) value); 
     break; 
    case 2: 
     .... 
    case 6: 

     it.setAlt((List<String>) value); 
     break; 
    } 
} 

@Override 
public Object getValueAt(int rowIndex, int columnIndex) { 
    Object returnValue = null; 
    item it = data.get(rowIndex); 

    switch (columnIndex) { 
    case 0: 
     returnValue = it.getNo(); 
     break; 
    case 1: 
     returnValue = it.getCode(); 
     break; 
    case 2: 
     ... 
    case 6: 
     returnValue = it.getAlt(); 
     break; 
    } 

    return returnValue; 
}  

public boolean isCellEditable(int rowIndex, int columnIndex) { 
    return columnIndex > 0; 
} 

最後的渲染器/編輯器類:

String[] sval = {"alfa", "Beta", "Gamma"}; //dummy array 

protected class ComboRenderer extends JComboBox implements TableCellRenderer { 

    public ComboRenderer(){ 
     super(sval);   //works, but this is not I want 
//  here should be used a similar super(list of options for a certain row), but how to get it? 
//  setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); 
     setOpaque(true); 
    } 


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

    if (isSelected) { 
       setForeground(table.getSelectionForeground()); 
       setBackground(table.getSelectionBackground()); 
     } else { 
       setForeground(table.getForeground()); 
       setBackground(table.getBackground()); 
     }   
     this.setSelectedItem(items); 
     return this; 
    } 

} 


protected class ComboEditor extends AbstractCellEditor 
implements TableCellEditor { 

    private List<String> alt; 

    protected ComboEditor() { 
     super(); 
    } 

    @Override 
    public Object getCellEditorValue() { 
     return this.alt; 
    } 

    @SuppressWarnings("unchecked") 
    @Override 
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { 
     if (value instanceof List) { 
      this.alt = (List<String>) value; 
     } 

     JComboBox<String> combo = new JComboBox<String>(); 
    // combo.setEditable(true); //does not work for editable combobox! 
     for (String a : alt) { 
      combo.addItem(a); 
     } 

     combo.setSelectedItem(alt); 

     if (isSelected) { 
      setForeground(table.getSelectionForeground()); 
      setBackground(table.getSelectionBackground()); 
     } else { 
      setForeground(table.getForeground()); 
      setBackground(table.getBackground()); 
     }   

     return combo; 
    } 

} 

而且這裏的問題:

1)渲染器對構造函數的錯誤部分(super(something))顯然不起作用。但在這部分我無法獲得渲染項目,所以我無法獲得初始化選項列表。如何解決這個問題?

2)編輯似乎工作正常,但當我從行中移動時,它再次顯示舊值。我應該在這裏保存些什麼?沒有新的數據,只是選擇可用於此項目的選項。

3)如何從外部達到某一行的選定值,比如打印?

4)如何獲得可編輯的Combobox而不是固定的?該生產線

// combo.setEditable(true); //does not work for editable combobox! 

不會在這種情況下

回答

0

在此期間我解決了這個問題的工作(除4號),但我認爲這必須是一個更好的解決辦法,所以我仍然在等待的替代解決方案。

對於第一,我注意到,因爲我得到了一個和渲染器的唯一實例中,

setSelectedItems(<available options>) 

返回值將返回在第一行的選擇對於所有其他行也一樣,無論什麼選擇有。所以我決定爲每一行創建一個渲染器實例。這意味着,JTable的構造函數將包含下面的代碼:

rendererList = new ArrayList<ComboRenderer>(); 
.... 
// create the Array of renderers, one for each row 
    for (int cnt=0; cnt<data.size(); cnt++){ 
     ComboRenderer a = new ComboRenderer(); 
     a.setOptions(cnt); 
     rendererList.add(a); 
    } 
.... 
// telling to JTable which renderer to use for every cell  
@Override 
public TableCellRenderer getCellRenderer(int row, int coll) { 
    if (coll==6) return rendererList.get(row); 
    else return this.getDefaultRenderer(this.getColumnClass(coll));  

} 

的渲染器和編輯器類現在看起來如下:

protected class ComboRenderer extends JComboBox implements TableCellRenderer { 

    List<String> items; 
    int selected; 
    //selected will contains the index of selected option, changed through the cell editor as listener 

    public ComboRenderer(){ 
     super(); 
     setOpaque(true); 
     selected=0; //initial value 
    } 

    public void setSel(int k) { 
     selected=k; 
    } 

    public int getSel() { 
     return selected; 
    } 
    // filling each renderer with available options; 
    @SuppressWarnings("unchecked") 
    public void setOptions(int row) { 
     items = data.get(row).getAlt(); 

     for (String a : items) { 
      this.addItem(a); 
     } 
    } 

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

     if (isSelected) { 
       setForeground(table.getSelectionForeground()); 
       setBackground(table.getSelectionBackground()); 
     } else { 
       setForeground(table.getForeground()); 
       setBackground(table.getBackground()); 
     }  
     this.setSelectedIndex(selected); 
     return this; 
    } 

} 


class ComboEditor extends AbstractCellEditor implements TableCellEditor{ 

    private List<String> alt ; 


    protected ComboEditor() { 
     super(); 
    } 

    @Override 
    public Object getCellEditorValue() { 
     return this.alt; 
    } 

    @SuppressWarnings("unchecked") 
    @Override 
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { 
     if (value instanceof List) { 
      this.alt = (List<String>) value; 
     } 

     JComboBox<String> combo = new JComboBox<String>(); 
     for (String a : alt) { 
      combo.addItem(a); 
     } 
     final ComboRenderer rend= rendererList.get(row); 
     // adding actionlistener to letting know the renderer the selection 
     combo.addActionListener(new ActionListener(){ 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       int i=((JComboBox<?>) arg0.getSource()).getSelectedIndex(); 
       // telling the renderer the selection  
       rend.setSel(i); 
      } 
     }); 

     combo.setSelectedIndex(rend.getSel()); 

     if (isSelected) { 
      setForeground(table.getSelectionForeground()); 
      setBackground(table.getSelectionBackground()); 
     } else { 
      setForeground(table.getForeground()); 
      setBackground(table.getBackground()); 
     }   

     return combo; 
    } 
} 

它現在的工作,但代碼看起來對我來說很笨拙。必須有辦法以更優雅的方式解決這個問題。我簡直不敢相信每一行都必須有獨特的渲染器,這是對內存的浪費。有沒有人有任何想法?